Neon’s project structure is the key to keeping your databases tidy, especially when you’re juggling multiple teams and environments. Think of projects as top-level containers, and within them, you’ll have your databases.
Here’s a typical setup you might see:
my-company-projects/
├── dev/
│ ├── frontend-team-db/
│ ├── backend-team-db/
│ └── data-science-team-db/
├── staging/
│ ├── frontend-team-db/
│ ├── backend-team-db/
│ └── data-science-team-db/
└── prod/
├── frontend-team-db/
├── backend-team-db/
└── data-science-team-db/
In this example, my-company-projects is a single Neon project. Inside, we have subdirectories representing environments: dev, staging, and prod. Each environment then contains databases for different teams.
To create this structure in Neon, you’d first create the main project, then create databases within it. You can use the Neon UI or the Neon API/CLI.
Let’s say you want to create the frontend-team-db in the dev environment.
Using the Neon UI:
- Navigate to your main Neon project (e.g.,
my-company-projects). - Click "Create database".
- In the "Database name" field, enter
frontend-team-db. - (Optional) You can add a description like "Development database for the frontend team."
- Click "Create".
Using the Neon CLI (assuming you have it installed and configured):
neonctl database create --project my-company-projects --name frontend-team-db
This command creates a database named frontend-team-db within the my-company-projects project. To distinguish it as a development database, you’d typically manage that distinction through your application’s configuration or by setting environment variables that point to the correct connection string for this specific database. Neon itself doesn’t enforce environment separation at the database name level directly, but your project and database naming conventions will facilitate it.
The real power comes when you start managing access. You can grant specific roles or users access to particular databases within a project. For instance, the frontend team’s CI/CD pipeline might only have read/write access to dev/frontend-team-db and staging/frontend-team-db, while the production deployment user has access to prod/frontend-team-db.
Consider a scenario where you have a large application and want to break down your monolithic database into smaller, more manageable services. You could create separate databases for user authentication, product catalog, order processing, etc., all within the same project or even within environment-specific sub-projects if your organization is structured that way.
Here’s how you might grant a specific role access to a database:
Using the Neon UI:
- Go to the database you want to manage (e.g.,
dev/frontend-team-db). - Navigate to the "Access" or "Roles" section.
- Select the role (e.g.,
frontend_developer_role) and grant it the necessary privileges (e.g.,READ WRITE).
Using SQL (connected to your database):
GRANT ALL PRIVILEGES ON DATABASE frontend_team_db TO frontend_developer_role;
This SQL command, executed as a superuser or a user with grant privileges, assigns all permissions on the frontend_team_db database to the role frontend_developer_role. This ensures that only authenticated users belonging to that role can interact with the database.
A common misconception is that projects are strictly for separating entirely different applications. While they can be used that way, they are often more granular, serving as logical groupings for related databases, especially when those databases share a common lifecycle or administrative oversight. For example, all databases for a single large microservice architecture might reside in one project, with distinct databases for each service, further segmented by environment.
When you’re setting up connection strings for your applications, you’ll reference the specific database name within the project. For instance, a development application might use a connection string like:
postgresql://<user>:<password>@ep-abc123xyz.us-east-1.aws.neon.tech:5432/frontend_team_db?options=...
And a production application would use a similar string, but pointing to the prod/frontend-team-db (or a different Neon project altogether, depending on your overall architecture).
The actual isolation between databases within a single Neon project is handled by PostgreSQL’s built-in multi-tenancy features. Each database is a distinct catalog. Neon manages the underlying infrastructure, ensuring that connections to different databases within the same project are routed correctly and that resources are allocated efficiently. When you create a new database, Neon provisions the necessary storage and compute resources for that specific database instance.
You might also use Neon’s branching feature to create isolated copies of your databases for testing specific features or bug fixes without impacting other environments or teams. A branch is essentially a point-in-time copy of a database that can be modified independently. You could create a branch from dev/frontend-team-db for a developer to experiment on, and if they like the changes, they can merge them back into the main development branch.
The ultimate goal of organizing databases by team and environment within Neon projects is to enhance security, improve manageability, and streamline development workflows. It allows for granular control over data access, simplifies resource allocation, and makes it easier to track which databases are used by which teams and for what purpose.
If you find yourself needing to manage separate billing or strict resource quotas for distinct applications or major business units, you would then consider creating entirely separate Neon projects for those.