Schemas are a great way to organize data in a PostgreSQL database. A schema allows you to group database objects such as tables, views, indexes and more into logical namespaces. This can help keep a complex database well structured.
In this comprehensive guide, we‘ll cover everything you need to know about creating schemas in PostgreSQL, including:
- What are schemas and why are they useful?
- How to create a schema
- Setting the schema owner
- Creating a schema if it doesn‘t exist
- Search path and current schema
- Creating objects inside schemas
- Altering schemas
- Dropping schemas
- Example use cases
What are PostgreSQL Schemas?
A schema is essentially a namespace that contains named database objects such as tables, views, indexes and more. Schema names begin with a letter and can contain letters, numbers and underscores.
Some key things to know about schemas:
- Schemas group together related database objects.
- You can only have one schema per database.
- Objects with the same name can exist in different schemas without conflict.
- The
publicschema is the default and is present in all databases.
Why Use Schemas?
Here are some of the main benefits of using schemas:
Logical grouping – As mentioned schemas allow you to group related objects. For example you may group forum tables under a forum schema.
Access control – Permissions can be granted on per schema basis, allowing restrictions on who can access what data.
Namespacing – Identically named objects can exist across schemas avoiding naming collisions. For example both forum and blog schemas can have a posts table.
In summary, schemas make it easier to manage permissions, organize related data, and avoid naming conflicts in large and complex databases.
Creating a Schema in PostgreSQL
The syntax to create a schema in SQL is:
CREATE SCHEMA schema_name;
For example to create a blog schema:
CREATE SCHEMA blog;
Let‘s look at some examples of creating schemas in PostgreSQL.
Create Schema Example
To demonstrate, we‘ll connect to a test database and create a simple blog schema:
postgres=# CREATE DATABASE testdb;
CREATE DATABASE
postgres=# \c testdb
testdb=# CREATE SCHEMA blog;
CREATE SCHEMA
And to verify it exists we can query the information_schema meta-data:
testdb=# SELECT schema_name FROM information_schema.schemata WHERE schema_name = ‘blog‘;
schema_name
-------------
blog
(1 row)
Setting Schema Owner
When a schema is created it will be owned by the user that created it.
You can also specify the owner using the AUTHORIZATION clause:
CREATE SCHEMA blog AUTHORIZATION someuser;
If the specified user doesn‘t exist you‘ll get an error.
Setting an owner allows you to later revoke rights and control who has access. By default the owner has full CREATE and USAGE rights on the schema.
Create Schema IF NOT EXISTS
It can be helpful to avoid errors by using IF NOT EXISTS when creating a schema. This will produce a notice instead of failing if it already exists:
testdb=# CREATE SCHEMA IF NOT EXISTS blog;
NOTICE: schema "blog" already exists, skipping
Current Schema vs Search Path
There are two important concepts that impact how schemas are accessed:
- The current schema
- The search path
The current schema is the default schema used for naming resolution if a schema is not specified.
You can view your current schema using:
testdb=# SHOW search_path;
search_path
-----------------
"$user", public
(1 row)
This brings us to the search path. The search path is an ordered list of schemas that are checked when an object is referenced without a schema prefix.
From our example above:
- First the
$userschema is checked (this will match the current user name) - Then
publicis checked
You can set the search path as needed:
SET search_path TO blog, public;
Generally you will want public present so all users can access the standard shared schema.
Now let‘s look at creating objects inside schemas.
Creating Objects in a Schema
Schemas themselves don‘t do much until you add objects like tables. The syntax for creating an object in a schema is:
schema.object
If no schema is specified then the current schema is used.
Let‘s create a posts table in our blog schema example:
testdb=# CREATE TABLE blog.posts (
id SERIAL PRIMARY KEY,
title VARCHAR(255) NOT NULL,
content TEXT
);
CREATE TABLE
Then to query the table, we need to reference the schema prefix blog.:
testdb=# SELECT * FROM blog.posts;
id | title | content
----+-------+---------
(0 rows)
This keeps things properly namespaced.
You can save some typing by setting the search path to include blog first. Then you can omit the schema prefix:
testdb=# SET search_path TO blog, public;
SET
testdb=# SELECT * FROM posts;
id | title | content
----+-------+---------
(0 rows)
Just keep in mind that mostly fully qualified names are considered better practice to avoid confusion.
Let‘s look at a couple more examples of creating objects inside schemas:
Create Table in Schema
Adding a table uses standard SQL syntax, specifying the schema name first:
CREATE TABLE schema.table (
...
);
For example:
CREATE TABLE blog.articles (
id SERIAL PRIMARY KEY,
title TEXT NOT NULL,
content TEXT
);
Create View in Schema
Much like tables, you can create views inside schemas:
CREATE VIEW blog.popular_articles AS
SELECT *
FROM blog.articles
WHERE views > 1000;
Create Function in Schema
Stored procedures, functions and other logic can also be namespaced by schema:
CREATE FUNCTION blog.get_article(id int)
RETURNS text AS $$
...
$$ LANGUAGE sql;
This keeps application logic organized as well.
Now that we have some objects created, let‘s look at managing schemas.
Altering Schemas
Occasionally you may need to modify a schema. Some common schema alterations include:
Rename Schema
The syntax to rename an existing schema is:
ALTER SCHEMA name RENAME TO new_name;
For example to rename blog to cms:
ALTER SCHEMA blog RENAME TO cms;
Any objects that reference the original schema name will need to be updated.
Change Schema Owner
To change the owner and transfer ownership of a schema:
ALTER SCHEMA name OWNER TO new_owner;
For example to set the owner of the cms schema to john:
ALTER SCHEMA cms OWNER TO john;
Now user john controls the schema and contained objects.
Let‘s look at removing schemas as well.
Dropping Schemas
To drop or remove a schema you would use:
DROP SCHEMA name;
However, PostgreSQL does not allow you to remove a schema that contains objects. You will get an error like:
ERROR: cannot drop schema cms because other objects depend on it
DETAIL: table cms.articles depends on schema cms
HINT: Use DROP ... CASCADE to drop the dependent objects too.
To overcome this you need to either:
- Manually drop all objects first
- Use
CASCADEto auto drop
Here is an example using CASCADE which will remove all containing objects:
DROP SCHEMA cms CASCADE;
And verification no longer exists:
SELECT schema_name FROM information_schema.schemata WHERE schema_name = ‘cms‘;
schema_name
-------------
(0 rows)
So in summary to delete a schema:
- Manually drop objects first
- Use
DROP SCHEMA ... CASCADE
PostgreSQL Schema Use Cases
Now that we have covered the basics of working with schemas let‘s look at some common use cases.
Schemas can help in many ways from access control to code organization and more.
Application Organization
Schemas make it very easy to group all objects for an application feature set.
For example if building a content management system (CMS) you may structure it as:
cmsschemaarticlestablecategoriestable- Article triggers, functions, etc
Keeping all CMS related logic under a single schema namespace separates it from other application database objects.
Multi-Tenant Apps
Schemas can be very useful for multi-tenant software where a single app serves multiple customers.
In this model you may create a separate schema per customer or organization. For example:
customer1customer2customer3
Then all core app tables like users, accounts, settings are created per schema. This avoids namespace collisions between nearly identically named entities. It also ensures customer data isolation from each other.
Legacy App Migrations
When migrating or upgrading legacy applications, the existing database objects can be moved into a separate legacy schema before being upgraded.
This provides easy access to the old dataset during migration phases. And avoids naming collisions with new versions of tables using the same identifiers.
Schema Migrations
In practice database changes are often done via schema migrations in a version control system. This allows safely applying incremental changes as code.
Migrations for schemas themselves can involve:
- Creating / dropping schemas
- Moving objects between schemas
- Renaming schemas
And schema migrations can be done alongside regular table / data migrations.
Permission Control
Wrapping application objects under a schema is a great way to manage database permissions.
Rather than granting direct table access, permissions can be granted on a per schema basis.
For example a app_read_only role can be granted usage on an app schema. This only allows visibility of the objects within that schema without altering data.
More granular rights can also be assigned, like allowing access to certain tables or columns as needed.
Conclusion
PostgreSQL schemas provide useful logical grouping and namespaces for database objects.
Some key points about schemas:
- Schemas group tables, views and other objects
- Sets of objects can be created inside schemas
- The same object names can exist in different schemas
- The default public schema always exists
- Schemas must be empty before dropping
In this guide we covered how to:
- Create and manage schemas
- Set a schema owner
- Create various objects within schemas
- Use schemas for permissions and organization
So in summary schemas are a very useful construct in SQL that helps avoid name collisions and better structure databases. They aid organization and access control for complex systems and applications.


