Skip to main content

VillageSQL is a drop-in replacement for MySQL with extensions.

All examples in this guide work on VillageSQL. Install Now →
A new Laravel 12 project ships with a commented-out MySQL connection block sitting directly under the active DB_CONNECTION line in .env, using the same host, port, database, username, and password shape every MySQL client expects. Uncommenting it and filling in real values is the entire integration. This guide walks through that setup end to end: connecting, running a migration, and reading and writing through Eloquent.

Creating the Project

This installs Laravel 12 and its dependencies, generates an application key, and creates a default SQLite database so the app runs immediately with no configuration. Confirm the version:
Laravel 12 requires PHP 8.2 or later. On macOS without PHP already installed, brew install php composer installs both; the Homebrew build of PHP 8.5 includes pdo_mysql and mysqli by default, so no extra extension setup is needed for MySQL.

Creating the Database and User

Create a dedicated database and a scoped user rather than pointing the application at root:

Configuring the Connection

Open .env and switch DB_CONNECTION from sqlite to mysql, then fill in the connection details:
Laravel connects over TCP to 127.0.0.1 here, the same host the CREATE USER statement above granted. VillageSQL is a drop-in replacement for MySQL, so nothing in config/database.php or the .env keys changes. config/database.php sets 'strict' => true on the mysql connection by default. This puts the session in MySQL’s standard strict SQL mode:
That mode set runs unchanged against VillageSQL. There is no strict-mode flag to disable or work around for compatibility.

Running Migrations

Laravel’s default migrations create the users, cache, and jobs tables. Run them against the configured connection:
Generate a model with its own migration for a posts table:
Add the title and body columns to the generated migration:
Run it, then confirm the table’s shape directly against the server:

Eloquent and Mass Assignment Protection

Laravel’s Eloquent models block mass assignment by default unless a field is listed in $fillable:
id, created_at, and updated_at are deliberately left out. Passing an id into create() doesn’t raise an error and doesn’t overwrite the value; Eloquent silently drops any key that isn’t in $fillable:
The row got the next auto-increment value, not 999. This matters when a store() method accepts a request body directly: without $fillable scoping the columns, a client could pass id or a timestamp field and have it accepted at face value. $fillable guards the model; request validation is a separate concern that checks the shape of the incoming data.

Routes and a Controller

Laravel 12’s default skeleton keeps routing minimal: routes/web.php holds the routes, and bootstrap/app.php wires up middleware and exception handling without the old Http/Kernel.php file. Generate a controller:
Register the routes:
routes/web.php runs behind Laravel’s session-based CSRF middleware, which rejects a plain curl -X POST with 419 Page Expired because the request carries no CSRF token. That is expected for a browser-facing form route; a real form posts the token via a hidden field. For a route meant to be called directly, without a form or a token, exclude it in bootstrap/app.php:

Verifying End to End

Start the built-in server and exercise both routes. The table already has the row from the $fillable demo above, so the index route returns it:
Confirm both rows landed by querying the database directly, rather than trusting the JSON responses alone:

Frequently Asked Questions

Why does Laravel default to SQLite instead of MySQL?

Recent Laravel versions default new projects to SQLite so php artisan serve works immediately with zero configuration. The .env file still carries the MySQL connection keys directly beneath the active DB_CONNECTION line, commented out. Switching to MySQL is a matter of uncommenting and filling in five values, not a new configuration section.

Does Eloquent need any special configuration to work with VillageSQL?

No. VillageSQL is a drop-in replacement for MySQL and speaks the same wire protocol, so Laravel’s mysql driver, its strict SQL mode setting, and its query grammar all work unchanged.

What’s the difference between $fillable and request validation?

$request->validate() decides which fields are accepted from the incoming request and rejects malformed input with a 422 response. $fillable on the model decides which of the fields you pass to create() or fill() are actually written to the database. Using $request->validate() alone still leaves the model open to mass assignment if a controller elsewhere calls Post::create($request->all()); $fillable protects the model regardless of which controller calls it.

Troubleshooting

See also