By WebNest Studio Engineering Team
PostgreSQL Tutorial
Schemas in PostgreSQL
In PostgreSQL, a schema is a namespace inside a database that groups tables, views, functions, and other objects together. This is a level of organization that sits between the database itself and individual objects — a single database can contain many schemas, and the same table name (like "users") can exist in two different schemas without conflict.
Schemas are frequently confused with databases by newcomers, but they serve a different purpose: they let you organize objects within one database (for example, separating "app" data from "reporting" views or "audit" logs) rather than isolating entirely separate databases from each other.
Why it matters
As a database grows, a single flat list of hundreds of tables becomes hard to manage. Schemas are namespaces inside a database: they group related tables, let two tables share a name, and are the unit on which permissions are commonly granted. Multi-tenant systems and applications with several modules use them constantly.
The public Schema
Every new PostgreSQL database is created with a default schema named public. When you run CREATE TABLE authors (...) without specifying a schema, PostgreSQL creates it as public.authors. This is why beginners rarely notice schemas at all — everything quietly lives in public until a project grows large enough to need separation.
Creating and Using Schemas
You create a schema with CREATE SCHEMA schema_name; and reference objects inside it with dot notation, such as reporting.monthly_sales. This lets teams logically separate concerns — for example, an auth schema for user/session tables, an app schema for business data, and an audit schema for change logs — all within a single database, with permissions grantable per schema.
search_path and Name Resolution
When you write an unqualified table name like SELECT * FROM orders, PostgreSQL looks through the schemas listed in the search_path setting, in order, until it finds a matching table. The default search_path is typically "$user", public. You can view or change it with SHOW search_path; and SET search_path TO app, public;. Understanding search_path matters because it silently determines which of several same-named tables in different schemas actually gets queried.
Example
Creating a schema and controlling search_path
CREATE SCHEMA reporting;
CREATE TABLE reporting.monthly_sales (
month DATE PRIMARY KEY,
total_sales NUMERIC(12,2)
);
SHOW search_path;
SET search_path TO reporting, public;
SELECT * FROM monthly_sales; -- resolves to reporting.monthly_sales
CREATE SCHEMA
CREATE TABLE
search_path
-----------------
"$user", public
SET
month | total_sales
-------+-------------
(0 rows)
Common Mistakes
- Assuming CREATE SCHEMA creates a new database — a schema is a namespace inside the current database, not a separate database.
- Relying on unqualified table names across schemas without checking search_path, then querying the wrong table entirely when two schemas both have a table with that name.
- Never granting schema-level USAGE privilege to a role, then wondering why a user with table-level GRANTs still cannot see the objects inside a non-public schema.
- Putting everything in public indefinitely on a growing project, making permissions and object discovery harder than they need to be.
Exercise
This exercise uses PostgreSQL schemas and search_path, so it needs a PostgreSQL server. Create a schema named sales and a table orders inside it. Insert a row using the fully qualified name. Then change the search path so that sales is searched first, and select from orders without the schema prefix.
Expected result: the final SELECT finds sales.orders without the prefix and returns the inserted row.
-- TODO: create the schema sales
-- TODO: create sales.orders (id integer primary key, total numeric)
-- TODO: insert a row using the qualified name
-- TODO: put sales first in the search path
-- TODO: select from orders without the prefix
Show hints
- A table in a schema is written
schema_name.table_name. - The search path is set with
SET search_path TO sales, public.
Show solution
CREATE SCHEMA sales;
CREATE TABLE sales.orders (
id INTEGER PRIMARY KEY,
total NUMERIC(10, 2)
);
INSERT INTO sales.orders (id, total) VALUES (1, 250.00);
SET search_path TO sales, public;
SELECT id, total FROM orders;
Quick quiz
1. In which schema is a table created when no schema is named, with the default settings?
- A. public
- B. pg_catalog
- C. default
- D. main
Show answer
A. It is the first schema in the default search path that exists.
2. What does search_path control?
- A. Where data files are stored on disk
- B. The order in which schemas are searched for an unqualified table name
- C. The order of query results
- D. The location of backups
Show answer
B. The first schema in the path that contains a matching name is used.
3. Can two tables with the same name exist in one database?
- A. No, never
- B. Only if they have different columns
- C. Yes, if they are in different schemas
- D. Only temporary tables
Show answer
C. A schema is a namespace, so sales.orders and archive.orders can coexist.
Interview questions
What is a schema in PostgreSQL and what is it used for?
Show answer
A schema is a named namespace inside a database that holds tables, views, functions and other objects. Schemas organise a large database into logical groups, allow objects in different groups to share a name, separate the data of different tenants or applications, and serve as a unit for permissions through GRANT ... ON SCHEMA. Unlike separate databases, objects in different schemas can be joined in one query.
What is the difference between a database and a schema in PostgreSQL?
Show answer
A database is the top-level container to which a client connects; a connection cannot query across databases. A schema lives inside a database and groups objects; one query can use tables from several schemas. Separate databases give strong isolation; schemas give organisation and name separation while keeping the data queryable together.
Key Points to Remember
- A schema is a namespace within a database; a database can hold many schemas.
- public is the default schema every new database starts with.
- search_path determines which schema an unqualified object name resolves to.
- Schemas are commonly used to separate concerns (app, auth, reporting) and to scope permissions cleanly.
Practice in the playground
Write and run your own code for this topic, or start from the exercise or an example. Runs your SQL on SQLite in your browser. Standard SQL works; a few features that exist only in PostgreSQL or MySQL do not. Your code for each topic is kept in this browser.
Run the examples
Change an input, predict the result, then compare it with the output. Explain why the result changes.
These examples need a project environment on your computer, so they can be copied but not run here. Codelab runs Python, FastAPI backends with SQLite, plain Java 17 and HTML/CSS/JavaScript.
Written by
WebNest Studio Engineering Team
Practical lessons from developers working with Java, Python, React, databases and production systems.
Led by Vansh Duggal, Founder, WebNest Studio · Full-stack & software engineering