Question

How to Add a New Column to an Existing Table in a Laravel Migration

phplaravellaravel-migrations

Question

I want to add a new column to an existing database table in Laravel, but I am not sure of the correct way to do it.

I tried editing a migration like this:

<?php

public function up()
{
    Schema::create('users', function ($table) {
        $table->integer('paid');
    });
}

Then in the terminal I ran:

php artisan migrate:install
php artisan migrate

How should I properly add a new column to an existing table in Laravel?

Short Answer

By the end of this page, you will understand how Laravel migrations work when a table already exists, why Schema::create() is not the right tool for modifying that table, and how to correctly add a new column using Schema::table() and a new migration file.

Concept

In Laravel, migrations are version-controlled instructions for changing your database structure over time. They let you create tables, add columns, remove columns, and update indexes in a safe, repeatable way.

The key idea in this question is:

  • Use Schema::create() when you are creating a table for the first time.
  • Use Schema::table() when the table already exists and you want to modify it.

If the users table already exists, calling Schema::create('users', ...) again is incorrect because Laravel will try to create a table that is already there.

To add a new column to an existing table, you should create a new migration rather than editing an old migration that may already have been run.

This matters because real projects evolve over time. Your database changes need to be:

  • trackable
  • reversible
  • safe for teammates and production servers

Laravel migrations give you that history. Each migration represents one database change.

Mental Model

Think of a migration like a list of construction jobs for a building:

  • Schema::create() means build a new room.
  • Schema::table() means renovate an existing room.

If the room already exists, you do not rebuild the whole room just to add one light switch. You send in a small renovation job that says, "add one switch to this room."

That is exactly what a new migration does when you add a column to an existing table.

Take Quiz

Syntax and Examples

To add a column to an existing table in Laravel, create a new migration and use Schema::table().

Basic syntax

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration {
    public function up(): void
    {
        Schema::table('users', function (Blueprint $table) {
            $table->integer('paid');
        });
    }

    public function down(): void
    {
        Schema::table('users', function (Blueprint $table) {
            $table->dropColumn('paid');
        });
    }
};

Create the migration file

php artisan make:migration add_paid_to_users_table --table=users

Laravel will generate a migration file for you. Then update it with the code above.

Run the migration

php artisan migrate

Example with a default value

If you want existing users to start with a value, you can do this:

Schema::table('users', function (Blueprint $table) {
    $table->boolean('paid')->default(false);
});

This is often better than a plain integer when the column represents a yes/no state.

Why this is better

  • It modifies the existing table safely.
  • It keeps a history of the database change.
  • It supports rollback through the down() method.

Step by Step Execution

Consider this migration:

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration {
    public function up(): void
    {
        Schema::table('users', function (Blueprint $table) {
            $table->boolean('paid')->default(false);
        });
    }

    public function down(): void
    {
        Schema::table('users', function (Blueprint $table) {
            $table->dropColumn('paid');
        });
    }
};

Here is what happens when you run php artisan migrate:

  1. Laravel checks the migrations table to see which migration files have already been run.
  2. It finds this new migration has not been executed yet.
  3. Laravel calls the up() method.
  4. Schema::table('users', ...) tells Laravel to modify the existing users table.
  5. $table->boolean('paid')->default(false); adds a new paid column.
  6. Laravel records that this migration has been run.

If you later run:

php artisan migrate:rollback

Laravel will:

  1. Find the most recent migration batch.
  2. Call the down() method.
  3. Remove the paid column using $table->dropColumn('paid');

This is what makes migrations reversible and safe to manage.

Real World Use Cases

Adding columns to existing tables is very common in real applications.

Common examples

  • User accounts: add paid, is_admin, last_login_at, or phone_number
  • E-commerce: add discount_code, shipped_at, or payment_status
  • Blog systems: add published_at, slug, or featured_image
  • APIs: add external_id, sync_status, or source
  • Analytics: add tracking_enabled or last_seen_at

Practical scenario

Suppose your app starts with basic user registration. Later, you launch paid memberships. Instead of rebuilding the users table, you create a new migration that adds a paid or subscription_status column.

That lets the database evolve with the application.

Take Quiz

Real Codebase Usage

In real Laravel codebases, developers usually follow these migration patterns:

1. Create a new migration for every schema change

Instead of changing an old migration that has already run, create a new one:

php artisan make:migration add_paid_to_users_table --table=users

This preserves history and works well across environments.

2. Use meaningful column types

Choose the type that matches the data:

  • boolean for true/false
  • integer for counts or numeric values
  • string for short text
  • timestamp or dateTime for dates

For a paid flag, boolean is often clearer than integer.

3. Use defaults when needed

If old rows already exist, a default value can avoid null-related issues:

$table->boolean('paid')->default(false);

4. Add nullable columns carefully

If you do not want a default yet:

$table->string('phone_number')->nullable();

5. Keep rollback logic complete

Always write the down() method when possible:

$table->dropColumn('paid');

This helps during development and deployment.

6. Pair schema changes with application updates

After adding a column, developers often also update:

  • Eloquent models
  • validation rules
  • form requests
  • seeders/factories
  • API resources
  • views or controllers

The migration changes the database, but the rest of the application may also need to understand the new field.

Common Mistakes

Here are common mistakes beginners make when adding columns in Laravel.

1. Using Schema::create() on an existing table

Broken code:

Schema::create('users', function ($table) {
    $table->integer('paid');
});

Why it is wrong:

  • create() is for new tables.
  • If users already exists, this will fail or behave incorrectly.

Use this instead:

Schema::table('users', function (Blueprint $table) {
    $table->integer('paid');
});

2. Editing an old migration after it already ran

If a migration has already been executed on your machine or another environment, changing it can cause mismatch problems.

Better approach:

  • keep the old migration as history
  • create a new migration for the new column

3. Running migrate:install unnecessarily

php artisan migrate:install creates the migrations repository table in older Laravel workflows. In most normal setups, you usually just run:

php artisan migrate

Do not use migrate:install every time you change the schema.

4. Forgetting the down() method

If you add a column in up() but do not remove it in down(), rollbacks become incomplete.

5. Choosing the wrong column type

If paid means yes or no, this may be better:

$table->boolean('paid')->default(false);

instead of:

$table->integer('paid');

6. Forgetting existing rows

If your table already has data, adding a non-nullable column without a default may cause issues depending on the database and schema.

Safer options:

$table->boolean('paid')->default(false);

or

$table->boolean('paid')->nullable();

Comparisons

TaskCorrect Laravel methodWhen to use it
Create a brand-new tableSchema::create()When the table does not exist yet
Add or change columns on an existing tableSchema::table()When the table already exists
Undo the latest migrationsphp artisan migrate:rollbackDuring development or rollback
Run pending migrationsphp artisan migrateApply new schema changes

integer('paid') vs boolean('paid')

Column typeBest forExample
integerNumeric values like counts, IDs, totalslogin_count, age, score
booleanTrue/false valuespaid, is_admin, active

Editing old migration vs creating new migration

ApproachRecommended?Why
Edit old migration already run in shared environmentsNoCan break migration history
Create a new migrationYesSafe, trackable, and reversible
Take Quiz

Cheat Sheet

# Create a migration to modify an existing table
php artisan make:migration add_paid_to_users_table --table=users

# Run migrations
php artisan migrate

# Roll back the latest batch
php artisan migrate:rollback
// Add a column to an existing table
Schema::table('users', function (Blueprint $table) {
    $table->boolean('paid')->default(false);
});
// Reverse the change
Schema::table('users', function (Blueprint $table) {
    $table->dropColumn('paid');
});

Rules to remember

  • Use Schema::create() for new tables.
  • Use Schema::table() for existing tables.
  • Usually create a new migration instead of editing an old one.
  • Add a down() method for rollback.
  • Pick the correct column type.
  • Consider default() or nullable() for existing records.

FAQ

How do I add a new column to an existing Laravel table?

Create a new migration with php artisan make:migration ... --table=table_name, then use Schema::table() inside the up() method.

Should I edit my old migration file to add a column?

If the migration has already been run, usually no. Create a new migration so the schema history stays consistent.

What is the difference between Schema::create() and Schema::table()?

Schema::create() makes a new table. Schema::table() changes a table that already exists.

Do I need to run php artisan migrate:install every time?

No. You normally just run php artisan migrate to apply new migrations.

Should paid be an integer or a boolean?

If it only means yes or no, boolean is usually the better choice.

What does the down() method do in a migration?

It defines how to undo the migration, such as removing the column that was added.

What happens if the table already has data?

Be careful with non-nullable columns. Use a default value or make the new column nullable if needed.

Take Quiz

Mini Project

Description

Build a small Laravel migration that adds an is_admin column to the existing users table. This mirrors a very common real-world task: updating the user schema as an application gains new roles or permissions.

Goal

Create and run a migration that adds a boolean column to an existing table and can also roll back cleanly.

Requirements

  1. Create a new migration for the users table.
  2. Add an is_admin column as a boolean.
  3. Set the default value to false.
  4. Implement the rollback logic to remove the column.
  5. Run the migration successfully.
Take Quiz

Keep learning

Related questions

View more