---
title: Schema migration with Neon Postgres and Laravel
subtitle: Set up Neon Postgres and run migrations for your Laravel project
enableTableOfContents: true
updatedOn: '2025-08-18T15:43:43.463Z'
---
[Laravel](https://laravel.com/) is a popular PHP web application framework that provides an expressive and elegant syntax for building web applications. It includes an ORM (Object-Relational Mapping) called Eloquent, which allows you to interact with databases using a fluent API. Laravel also provides a powerful migration system to manage database schema changes over time.
This guide demonstrates how to use Laravel with the Neon Postgres database. We'll create a simple Laravel application and walk through the process of setting up the database, defining models, and generating and running migrations to manage schema changes.
## Prerequisites
To follow along with this guide, you will need:
- A Neon account. If you do not have one, sign up at [Neon](https://neon.tech). Your Neon project comes with a ready-to-use Postgres database named `neondb`. We'll use this database in the following examples.
- [PHP](https://www.php.net/) installed on your local machine. This guide uses PHP 8.1, but you can use any recent version compatible with Laravel.
- [Composer](https://getcomposer.org/) installed on your local machine for managing PHP dependencies.
## Setting up your Neon database
### Initialize a new project
1. Log in to the Neon Console and navigate to the [Projects](https://console.neon.tech/app/projects) section.
2. Select a project or click the **New Project** button to create a new one.
### Retrieve your Neon database connection string
Find your database connection string by clicking the **Connect** button on your **Project Dashboard** to open the **Connect to your database** modal. It should look similar to this:
```bash
postgresql://alex:AbC123dEf@ep-cool-darkness-123456.us-east-2.aws.neon.tech/dbname?sslmode=require&channel_binding=require
```
Neon supports both direct and pooled database connection strings, which you can find by clicking the **Connect** button on your **Project Dashboard** to open the **Connect to your database** modal. 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](/docs/connect/connection-pooling).
Keep your connection string handy for later use.
## Setting up the Laravel project
### Create a new Laravel project
Open your terminal and navigate to the directory where you want to create your Laravel project. Run the following command to create a new Laravel project:
```bash
composer create-project --prefer-dist laravel/laravel guide-neon-laravel
```
This command creates a new Laravel project named `guide-neon-laravel` in the current directory.
### Set up the Database configuration
Open the `.env` file in the project root directory and update the following database connection variables:
```bash
DB_CONNECTION=pgsql
DB_PORT=5432
DATABASE_URL=NEON_POSTGRES_CONNECTION_STRING
```
Replace `NEON_POSTGRES_CONNECTION_STRING` with the connection string you retrieved from the Neon Console earlier. The `DB_CONNECTION` should be set to `pgsql` to indicate that we are using a Postgres database.
## Defining data models and running migrations
### Specify the data model
Data models are defined using the `Elquent` ORM in Laravel. Our application is a simple catalog of authors and books, where each author can have multiple books. We'll create two models, `Author` and `Book`, to represent the data.
Create a new file `Author.php` in the `app/Models` directory with the following code:
```php
hasMany(Book::class);
}
}
```
Create another file `Book.php` in the `app/Models` directory with the following code:
```php
belongsTo(Author::class);
}
}
```
The `Author` model represents an author with fields for name and bio. The `Book` model represents a book with fields for title and author (as a foreign key to the `Author` model). Laravel automatically creates an `id` field for each model as the primary key and manages the `created_at` and `updated_at` timestamps.
### Generate migration files
To generate migration files for creating the `authors` and `books` tables, run the following commands in the terminal:
```bash
php artisan make:migration create_authors_table
php artisan make:migration create_books_table
```
These commands generate empty migration files in the `database/migrations` directory. Unlike frameworks such as Django, Laravel does not generate the schema automatically based on the model definitions. Instead, you define the schema in the migration files.
Open the `create_authors_table` migration file and update the `up` method to define the table schema:
```php
public function up()
{
Schema::create('authors', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->text('bio')->nullable();
$table->timestamps();
});
}
```
Similarly, open the `create_books_table` migration file and update the `up` method:
```php
public function up()
{
Schema::create('books', function (Blueprint $table) {
$table->id();
$table->string('title');
$table->unsignedBigInteger('author_id');
$table->timestamps();
$table->foreign('author_id')->references('id')->on('authors')->onDelete('cascade');
});
}
```
### Apply the migration
To apply the migration and create the corresponding tables in the Neon Postgres database, run the following command:
```bash
php artisan migrate
```
This command executes the migration files and creates the `authors` and `books` tables in the database.
### Seed the database
To populate the database with some initial data, we use Laravel's database seeding feature. Open the file `DatabaseSeeder.php` in the `database/seeders` directory and replace its contents with the following code:
```php
'J.R.R. Tolkien',
'bio' => 'The creator of Middle-earth and author of The Lord of the Rings.',
'books' => [
['title' => 'The Fellowship of the Ring'],
['title' => 'The Two Towers'],
['title' => 'The Return of the King'],
],
],
[
'name' => 'George R.R. Martin',
'bio' => 'The author of the epic fantasy series A Song of Ice and Fire.',
'books' => [
['title' => 'A Game of Thrones'],
['title' => 'A Clash of Kings'],
['title' => 'A Storm of Swords'],
],
],
[
'name' => 'J.K. Rowling',
'bio' => 'The creator of the Harry Potter series.',
'books' => [
['title' => 'Harry Potter and the Philosopher\'s Stone'],
['title' => 'Harry Potter and the Chamber of Secrets'],
],
],
];
foreach ($authors as $authorData) {
$author = Author::create([
'name' => $authorData['name'],
'bio' => $authorData['bio'],
]);
foreach ($authorData['books'] as $bookData) {
$author->books()->create($bookData);
}
}
}
}
```
This seeder creates three authors and associates them with their corresponding books. To run this script and populate the database, run the following command in the terminal:
```bash
php artisan db:seed
```
## Implement the application
### Create routes and controllers
We'll create two routes and corresponding controllers to display the authors and books in our application.
Open the `routes/web.php` file and add the following routes:
```php
...
use App\Http\Controllers\AuthorController;
use App\Http\Controllers\BookController;
...
Route::get('/authors', [AuthorController::class, 'index'])->name('authors.index');
Route::get('/books/{author}', [BookController::class, 'index'])->name('books.index');
```
We define two routes: `/authors` to list all authors and `/books/{author}` to list books by a specific author.
Now, create a new file `AuthorController.php` in the `app/Http/Controllers` directory with the following code:
```php
json($authors);
}
}
```
Similarly, create another file `BookController.php` in the `app/Http/Controllers` directory with the following code:
```php
books;
return response()->json($books);
}
}
```
These controllers define the `index` action to retrieve all authors and books by a specific author, respectively. The data is returned as JSON responses.
### Run the Laravel development server
To start the Laravel development server and test the application, run the following command:
```bash
php artisan serve
```
Navigate to the url `http://localhost:8000/authors` in your browser to view the list of authors. You can also view the books by a specific author by visiting `http://localhost:8000/books/{author_id}`.
## Applying schema changes
We will demonstrate how to handle schema changes by adding a new field `country` to the `Author` model, which will store the author's country of origin.
### Update the data model
Open the `Author.php` file in the `app/Models` directory and add the `country` field to the `$fillable` property:
```php
protected $fillable = ['name', 'bio', 'country'];
```
### Generate and run the migration
To generate a new migration file for the schema change, run the following command:
```bash
php artisan make:migration add_country_to_authors_table
```
This command generates a new migration file in the `database/migrations` directory.
Open the generated migration file and update the `up` method to add the new `country` column:
```php
public function up()
{
Schema::table('authors', function (Blueprint $table) {
$table->string('country')->nullable()->after('bio');
});
}
```
Now, to apply the migration, run the following command:
```bash
php artisan migrate
```
### Test the schema change
Restart the Laravel development server:
```bash
php artisan serve
```
Navigate to the url `http://localhost:8000/authors` to view the list of authors. Each author entry now includes the `country` field set to `null`, reflecting the schema change.
## Conclusion
In this guide, we demonstrated how to set up a Laravel project with `Neon` Postgres, define database models using Eloquent, generate migrations, and run them. Laravel's Eloquent ORM and migration system make 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.
Migrations with Neon and Laravel
## Resources
For more information on the tools and concepts used in this guide, refer to the following resources:
- [Laravel Documentation](https://laravel.com/docs)
- [Neon Postgres](/docs/introduction)