Schema migration with Neon Postgres and SQLAlchemy
Manage database migrations in your Python project with SQLAlchemy and Alembic
SQLAlchemy is a popular SQL toolkit and Object-Relational Mapping (ORM) library for Python. SQLAlchemy provides a powerful way to interact with databases and manage database schema changes using Alembic, a lightweight database migration tool.
This guide demonstrates how to use SQLAlchemy/Alembic to manage schema migrations for a Neon Postgres database. We create a simple API using the FastAPI web framework and define database models using SQLAlchemy. We then generate and run migrations to manage schema changes over time.
Prerequisites
To follow along with this guide, you will need:
- A Neon account. If you do not have one, sign up at Neon. Your Neon project comes with a ready-to-use Postgres database named
neondb
. We'll use this database in the following examples. - Python installed on your local machine. We recommend using a newer version of Python, 3.8 or higher.
Setting up your Neon database
Initialize a new project
- Log in to the Neon Console and navigate to the Projects section.
- Select a project or click the New Project button to create a new one.
Retrieve your Neon database connection string
Navigate to the Connection Details section to find your database connection string. It should look similar to this:
Keep your connection string handy for later use.
note
Neon supports both direct and pooled database connection strings, which can be copied from the Connection Details widget on your Neon Project Dashboard. A pooled connection string connects your application to the database via a PgBouncer connection pool, allowing for a higher number of concurrent connections. However, using a pooled connection string for migrations can be prone to errors. For this reason, we recommend using a direct (non-pooled) connection when performing migrations. For more information about direct and pooled connections, see Connection pooling.
Setting up the Web application
Set up the Python environment
To manage our project dependencies, we create a new Python virtual environment. Run the following commands in your terminal to set it up.
Activate the virtual environment by running the following command:
With the virtual environment activated, we can create a new directory for our FastAPI project and install the required packages:
We installed SQLAlchemy, Alembic, and the psycopg2-binary
package to connect to the Neon Postgres database. We the installed the FastAPI
package to create the API endpoints and uvicorn
as the web server. We then saved the installed packages to a requirements.txt
file so the project can be easily recreated in another environment.
Set up the Database configuration
Create a .env
file in the project root directory and add the DATABASE_URL
environment variable to it. Use the connection string that you obtained from the Neon Console earlier:
We create an app
directory at the project root to store the database models and configuration files.
Next, create a new file named database.py
in the app
subdirectory and add the following code:
This code sets up the database connection using SQLAlchemy. It reads the DATABASE_URL
environment variable, creates a database engine, and defines a SessionLocal
class for database sessions. The Base
class is used as a base class for defining database models.
Defining data models and running migrations
Specify the data model
Create a new file named models.py
in the app
subdirectory and define the database models for your application:
This code defines two models: Author
and Book
. The Author
model represents an author with fields for name
, bio
, and a created_at
timestamp. The Book
model represents a book with fields for title
, author
(as a foreign key to the Author
model), and a created_at
timestamp. The relationship
function is used to define the one-to-many relationship between Author
and Book
.
Initialize Alembic
To initialize Alembic for managing database migrations, run the following command in your terminal:
This command creates a new directory named alembic
with the necessary files for managing migrations. Open the env.py
file in the alembic
directory and update the target_metadata
variable to include the models defined in the models.py
file:
We update the alembic/env.py
file again to load the database URL from the .env
file at project root and set it as the sqlalchemy.url
configuration option.
Generate the initial migration
To generate the initial migration based on the defined models, run the following command:
This command detects the Author
and Book
models and generates a new migration file in the alembic/versions
directory.
Apply the migration
To apply the migration and create the corresponding tables in the Neon Postgres database, run the following command:
This command executes the migration file and creates the necessary tables in the database.
Seed the database
To seed the database with some initial data, create a new file named seed.py
in the project root and add the following code:
Now, run the seed.py
script to seed the database with the initial data:
Implement the web application
Create API endpoints
Create a file named main.py
in the project root directory and define the FastAPI application with endpoints for interacting with authors and books:
This code defines endpoints for creating and retrieving authors and books. It uses SQLAlchemy's Session
to interact with the database and Pydantic models (schemas
) for request and response data validation and serialization.
Run the FastAPI server
To start the FastAPI server using uvicorn
and test the application, run the following command:
Now, you can navigate to http://localhost:8000/authors
in your browser to view the list of authors. To view the books by a specific author, navigate to http://localhost:8000/books/{author_id}
where {author_id}
is the ID of the author.
Applying schema changes
Let's demonstrate how to handle schema changes by adding a new field country
to the Author
model, to store the author's country of origin.
Update the data model
Open the models.py
file and add a new field to the Author
model:
Generate and run the migration
To generate a new migration file for the schema change, run the following command:
This command detects the updated Author
model and generates a new migration file to add the new field to the corresponding table in the database.
Now, to apply the migration, run the following command:
Test the schema change
Restart the FastAPI development server.
Navigate to http://localhost:8000/authors
in your browser to view the list of authors. You should see the new country
field included in each author's record, reflecting the schema change.
Conclusion
In this guide, we demonstrated how to set up a FastAPI project with Neon
Postgres, define database models using SQLAlchemy, generate migrations using Alembic, and run them. Alembic makes it easy to interact with the database and manage schema evolution over time.
Source code
You can find the source code for the application described in this guide on GitHub.
Resources
For more information on the tools and concepts used in this guide, refer to the following resources:
Need help?
Join our Discord Server to ask questions or see what others are doing with Neon. Users on paid plans can open a support ticket from the console. For more detail, see Getting Support.