PHPackages                             pmatseykanets/laravel-sql-migrations - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Database &amp; ORM](/categories/database)
4. /
5. pmatseykanets/laravel-sql-migrations

ActiveLibrary[Database &amp; ORM](/categories/database)

pmatseykanets/laravel-sql-migrations
====================================

Raw SQL migrations for Laravel

v1.2.0(4y ago)3432.5k↑43.8%9[1 issues](https://github.com/pmatseykanets/laravel-sql-migrations/issues)[2 PRs](https://github.com/pmatseykanets/laravel-sql-migrations/pulls)MITPHPPHP ^7.2|^8.0.2CI failing

Since Jun 18Pushed 2y ago3 watchersCompare

[ Source](https://github.com/pmatseykanets/laravel-sql-migrations)[ Packagist](https://packagist.org/packages/pmatseykanets/laravel-sql-migrations)[ Docs](https://github.com/pmatseykanets/laravel-sql-migrations)[ RSS](/packages/pmatseykanets-laravel-sql-migrations/feed)WikiDiscussions master Synced 1mo ago

READMEChangelog (7)Dependencies (3)Versions (9)Used By (0)

laravel-sql-migrations
======================

[](#laravel-sql-migrations)

[![tests](https://github.com/pmatseykanets/laravel-sql-migrations/workflows/tests/badge.svg)](https://github.com/pmatseykanets/laravel-sql-migrations/workflows/tests/badge.svg)[![Total Downloads](https://camo.githubusercontent.com/3f28b6feb9f1597f9b5c6674e73f9988289d34dec19e420d1d8b6bcef7b068b5/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f706d61747365796b616e6574732f6c61726176656c2d73716c2d6d6967726174696f6e732e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/pmatseykanets/laravel-sql-migrations)

Write your Laravel migrations in plain SQL.

If you find this package usefull, please consider bying me a coffee.

[![Buy Me a Coffee at ko-fi.com](https://camo.githubusercontent.com/154f15d832baabe75153bc6f3f3923cdd4eda07ed77efd80d92544ee1c381ddf/68747470733a2f2f63646e2e6b6f2d66692e636f6d2f63646e2f6b6f6669322e706e673f763d32)](https://ko-fi.com/V7V43MXAO)

Contents
--------

[](#contents)

- [Why](#why)
- [Installation](#installation)
- [Usage](#usage)
    - [Make SQL Migrations](#make-sql-migrations)
    - [Run SQL Migrations](#run-sql-migrations)
- [Example Projects](#example-projects)
- [Changelog](#changelog)
- [Contributing](#contributing)
- [Credits](#credits)
- [License](#license)

Why
---

[](#why)

Don't get me wrong, the Laravel's [`SchemaBuilder`](https://laravel.com/docs/master/migrations) is absolutely great and you can get a lot of millage out of it.

But there are cases when it's just standing in the way. Below are just a few examples where `SchemaBuilder` falls short.

### Using additional / richer data types

[](#using-additional--richer-data-types)

I.e. if you're using [PostgreSQL](https://www.postgresql.org/) and you want to use a case insensitive data type for string/text data you may consider `CITEXT`. This means that we have to resort to a hack like this

```
class CreateUsersTable extends Migration
{
    public function up()
    {
        Schema::create('users', function (Blueprint $table) {
            $table->bigIncrement('id');
            $table->string('email')->unique();
            // ...
        });

        DB::unprepared('ALTER TABLE users ALTER COLUMN email TYPE CITEXT');
    }
}
```

instead of just

```
CREATE TABLE IF NOT EXISTS users (
    id BIGSERIAL PRIMARY KEY,
    email CITEXT UNIQUE,
    ...
);
```

Of course there are plenty of other data types (i.e. [Range](https://www.postgresql.org/docs/current/static/rangetypes.html) or [Text Search](https://www.postgresql.org/docs/current/static/datatype-textsearch.html) data types in PostgreSQL) that might be very useful but `SchemaBuilder` is unaware of and never will be.

### Managing stored functions, procedures and triggers

[](#managing-stored-functions-procedures-and-triggers)

This is a big one, especially if you're still using reverse (`down()`) migrations. This means that you need to cram both new and old source code of a function/procedure/trigger in `up()` and `down()` methods of your migration file and keep them in string variables which doesn't help with readability/maintainability.

Even with [`heredoc` / `nowdoc`](https://secure.php.net/manual/en/language.types.string.php) syntax in `php` it's still gross.

### Taking advantage of `IF [NOT] EXISTS` and alike

[](#taking-advantage-of-if-not-exists-and-alike)

There is a multitude of important and useful SQL standard compliant and vendor specific clauses in DDL statements that can make your life so much easier. One of the well known and frequently used ones is `IF [NOT] EXISTS`.

Instead of letting `ShemaBuilder` doing a separate query(ies) to `information_schema`

```
if (! Schema::hasTable('users')) {
    // create the table
}

if (! Schema::hasColumn('users', 'notes')) {
    // create the column
}
```

you can just write it natively in one statement

```
CREATE TABLE IF NOT EXISTS users (id BIGSERIAL PRIMARY KEY, ...);
ALTER TABLE users ADD IF NOT EXISTS notes TEXT;
```

### Using additional options when creating indexes

[](#using-additional-options-when-creating-indexes)

Some databases (i.e. PostgreSQL) allow you to (re)create indexes concurrently without locking your table.

```
CREATE INDEX CONCURRENTLY IF NOT EXISTS some_big_table_important_column_id
    ON some_big_table (important_column);

CREATE INDEX IF NOT EXISTS table_json_column_idx USING GIN ON table (json_column);
```

You may need to create a specific type of index instead of a default `btree`

```
CREATE INDEX IF NOT EXISTS some_table_json_column_idx ON some_table (json_column) USING GIN;
```

Or create a partial/functional index

```
CREATE INDEX IF NOT EXISTS some_table_nullable_column_idx
    ON some_table (nullable_column)
    WHERE nullable_column IS NOT NULL;
```

### Taking advantage of database native procedural code (i.e. PL/pgSQL)

[](#taking-advantage-of-database-native-procedural-code-ie-plpgsql)

When using PostgreSQL you can use an anonymous [PL/pgSQL](https://www.postgresql.org/docs/current/static/plpgsql.html) code block if you need to. I.e. dynamically (without knowing the database name ahead of time) set `search_path` if you want to install all extensions in a dedicated schema instead of polluting `public`.

The `.up.sql` migration could look like:

```
DO $$
BEGIN
  EXECUTE 'ALTER DATABASE ' || current_database() || ' SET search_path TO "$user",public,extensions';
END;
$$;
```

and the reverse `.down.sql`:

```
DO $$
BEGIN
  EXECUTE 'ALTER DATABASE ' || current_database() || ' SET search_path TO "$user",public';
END;
$$;
```

Installation
------------

[](#installation)

You can install the package via composer:

```
composer require pmatseykanets/laravel-sql-migrations
```

If you're using Laravel &lt; 5.5 or if you have package auto-discovery turned off you have to manually register the service provider:

```
// config/app.php
'providers' => [
    ...
    SqlMigrations\SqlMigrationsServiceProvider::class,
],
```

Usage
-----

[](#usage)

### Make SQL migrations

[](#make-sql-migrations)

The most convenient way of creating SQL migrations is to use `artisan make:migration` with **`--sql`** option

```
php artisan make:migration create_users_table --sql
```

which will produce three files

```
database
└── migrations
    ├── 2018_06_15_000000_create_users_table.down.sql
    ├── 2018_06_15_000000_create_users_table.php
    └── 2018_06_15_000000_create_users_table.up.sql
```

*I know, it bloats `migrations` directory with additional files but this approach allows you to mix and match traditional and plain SQL migrations easily. If it's any consolation if you don't use reverse (`down`) migrations you can just delete `*.down.sql` file(s).*

**Note:** if you're creating files manually make sure that:

1. The base `php` migration class extends `SqlMigration` class and doesn't contain `up()` and `down()` methods, unless you mean to override the default behavior.
2. The filename (without extension) of `.up.sql` and `.down.sql` files matches exactly (including the timestamp part) the filename of the base `php` migration.

At this point you can forget about `2018_06_15_000000_create_users_table.php` unless you want to configure or override behavior of this particular migration.

`SqlMigration` extends the built-in `Migration` so you can fine tune your migration in the same way

```
class CreateNextIdFunction extends SqlMigration
{
    // Use a non default connection
    public $connection = 'pgsql2';
    // Wrap migration in a transaction if the database suports transactional DDL
    public $withinTransaction = true;
}
```

Now go ahead open up `*.sql` files and write your migration code.

I.e. `2018_06_15_000000_create_users_table.up.sql` might look along the lines of

```
CREATE TABLE IF NOT EXISTS users (
    id BIGSERIAL PRIMARY KEY,
    name CITEXT,
    email CITEXT,
    password TEXT,
    remember_token TEXT,
    created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP
);

CREATE UNIQUE INDEX IF NOT EXISTS users_email_idx ON users (email);
```

and `2018_06_15_000000_create_users_table.down.sql`

```
DROP TABLE IF EXISTS users;
```

You can also pass `--sql` option to `make:model` artisan command to instruct it to create plain SQL migrations for your newly created model.

```
php artisan make:model Post --migration --sql
```

### Run SQL migrations

[](#run-sql-migrations)

Proceed as usual using `migrate`, `migrate:rollback` and other built-in commands.

Example Projects
----------------

[](#example-projects)

You can find bare Laravel 5.6 projects with default SQL migrations here:

- [PostgreSQL](https://github.com/pmatseykanets/laravel-sql-migrations-example-postgres)
- [MySQL](https://github.com/pmatseykanets/laravel-sql-migrations-example-mysql)

Changelog
---------

[](#changelog)

Please see [CHANGELOG](CHANGELOG.md) for more information about what has changed recently.

Contributing
------------

[](#contributing)

Please see [CONTRIBUTING](CONTRIBUTING.md) for details.

Credits
-------

[](#credits)

- [Peter Matseykanets](https://github.com/pmatseykanets)
- [All Contributors](../../contributors)

License
-------

[](#license)

The MIT License (MIT). Please see [License File](LICENSE.md) for more information.

###  Health Score

40

—

FairBetter than 88% of packages

Maintenance19

Infrequent updates — may be unmaintained

Popularity39

Limited adoption so far

Community12

Small or concentrated contributor base

Maturity73

Established project with proven stability

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~236 days

Recently: every ~321 days

Total

7

Last Release

1474d ago

Major Versions

v0.4.0 → v1.0.02020-11-26

PHP version history (4 changes)v0.1.0PHP &gt;=7.1.3

v0.4.0PHP ^7.2

v1.1.0PHP ^7.2|^8.0

v1.2.0PHP ^7.2|^8.0.2

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/779965?v=4)[Peter Matseykanets](/maintainers/pmatseykanets)[@pmatseykanets](https://github.com/pmatseykanets)

---

Top Contributors

[![pmatseykanets](https://avatars.githubusercontent.com/u/779965?v=4)](https://github.com/pmatseykanets "pmatseykanets (38 commits)")

---

Tags

laravelmigrationssql

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/pmatseykanets-laravel-sql-migrations/health.svg)

```
[![Health](https://phpackages.com/badges/pmatseykanets-laravel-sql-migrations/health.svg)](https://phpackages.com/packages/pmatseykanets-laravel-sql-migrations)
```

###  Alternatives

[anourvalar/eloquent-serialize

Laravel Query Builder (Eloquent) serialization

11120.2M21](/packages/anourvalar-eloquent-serialize)[overtrue/laravel-versionable

Make Laravel model versionable.

585308.0k5](/packages/overtrue-laravel-versionable)[abbasudo/laravel-purity

elegant way to add filter and sort in laravel

514330.5k1](/packages/abbasudo-laravel-purity)[statamic-rad-pack/runway

Eloquently manage your database models in Statamic.

135192.6k5](/packages/statamic-rad-pack-runway)[dragon-code/laravel-deploy-operations

Performing any actions during the deployment process

240173.5k2](/packages/dragon-code-laravel-deploy-operations)[stayallive/laravel-eloquent-observable

Register Eloquent model event listeners just-in-time directly from the model.

2928.9k7](/packages/stayallive-laravel-eloquent-observable)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
