VillageSQL is a drop-in replacement for MySQL with extensions.
All examples in this guide work on VillageSQL. Install Now →
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
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 atroot:
Configuring the Connection
Open.env and switch DB_CONNECTION from sqlite to mysql, then fill in the connection details:
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:
Running Migrations
Laravel’s default migrations create theusers, cache, and jobs tables. Run them against the configured connection:
posts table:
title and body columns to the generated migration:
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:
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:
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:
Frequently Asked Questions
Why does Laravel default to SQLite instead of MySQL?
Recent Laravel versions default new projects to SQLite sophp 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’smysql 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
- Using MySQL with ORMs: Django, Rails, and Prisma — the same connection-level settings and N+1 patterns from an ORM-agnostic angle
- Schema Migrations in MySQL — what Laravel’s migration files are doing to the table underneath
ALTER TABLE - MySQL Connection Pooling — configuring persistent connections for a Laravel app under real traffic

