laravel/laravel
Database
Active contributors: Taylor Otwell, Jack Bayliss, Nuno Maduro
Purpose
database/ ships the schema, fixtures, and seeders. Three migrations define the ten baseline tables that the framework's defaults depend on; one factory produces fake users; one seeder seeds a single test user. SQLite is the default connection — the .env.example points there and the composer.json post-create-project-cmd touches database/database.sqlite so it exists out of the box.
Directory layout
database/
├── .gitignore # Excludes database.sqlite
├── factories/
│ └── UserFactory.php
├── migrations/
│ ├── 0001_01_01_000000_create_users_table.php
│ ├── 0001_01_01_000001_create_cache_table.php
│ └── 0001_01_01_000002_create_jobs_table.php
└── seeders/
└── DatabaseSeeder.phpThe three baseline migrations
The skeleton uses anonymous-class migrations (return new class extends Migration) — no class names to manage. Each file groups related tables.
0001_01_01_000000_create_users_table.php
Creates three tables in one migration:
| Table | Columns | Used by |
|---|---|---|
users |
id, name, email (unique), email_verified_at (nullable), password, remember_token, timestamps |
App\Models\User, web auth guard |
password_reset_tokens |
email (PK), token, created_at (nullable) |
Auth::sendPasswordResetLink() |
sessions |
id (PK), user_id (nullable, indexed), ip_address, user_agent, payload (longText), last_activity (indexed) |
database session driver |
The down() method drops all three in reverse order.
0001_01_01_000001_create_cache_table.php
| Table | Columns | Used by |
|---|---|---|
cache |
key (PK), value (mediumText), expiration (indexed) |
database cache store |
cache_locks |
key (PK), owner, expiration (indexed) |
Cache::lock() atomic locks |
0001_01_01_000002_create_jobs_table.php
| Table | Columns | Used by |
|---|---|---|
jobs |
id, queue (indexed), payload, attempts, reserved_at (nullable), available_at, created_at |
database queue connection |
job_batches |
id (PK), name, total_jobs, pending_jobs, failed_jobs, failed_job_ids, options, cancelled_at, created_at, finished_at |
Bus::batch(...) job batches |
failed_jobs |
id, uuid (unique), connection, queue, payload, exception, failed_at (defaults to current ts) |
database-uuids failed-job driver |
Note that v12.11.2 (CHANGELOG.md) merged "Update jobs/cache migrations" and "Remove failed jobs indexes" PRs (#6736, #6739). The current files are the result of that consolidation.
Schema diagram
erDiagram
USERS ||--o{ SESSIONS : has
USERS {
bigint id PK
string name
string email UK
timestamp email_verified_at
string password
string remember_token
timestamps timestamps
}
PASSWORD_RESET_TOKENS {
string email PK
string token
timestamp created_at
}
SESSIONS {
string id PK
bigint user_id FK
string ip_address
text user_agent
longtext payload
int last_activity
}
CACHE {
string key PK
mediumtext value
bigint expiration
}
CACHE_LOCKS {
string key PK
string owner
bigint expiration
}
JOBS {
bigint id PK
string queue
longtext payload
smallint attempts
int reserved_at
int available_at
int created_at
}
JOB_BATCHES {
string id PK
string name
int total_jobs
int pending_jobs
int failed_jobs
longtext failed_job_ids
mediumtext options
int cancelled_at
int created_at
int finished_at
}
FAILED_JOBS {
bigint id PK
string uuid UK
text connection
text queue
longtext payload
longtext exception
timestamp failed_at
}database/factories/UserFactory.php
Defines a default state for App\Models\User:
public function definition(): array
{
return [
'name' => fake()->name(),
'email' => fake()->unique()->safeEmail(),
'email_verified_at' => now(),
'password' => static::$password ??= Hash::make('password'),
'remember_token' => Str::random(10),
];
}The cached static $password ensures every fake user shares the same bcrypt hash, which is the slow operation. Subsequent factory calls reuse it instead of re-hashing.
A second helper:
public function unverified(): static
{
return $this->state(fn (array $attributes) => [
'email_verified_at' => null,
]);
}Used in tests with User::factory()->unverified()->create().
database/seeders/DatabaseSeeder.php
public function run(): void
{
// User::factory(10)->create();
User::factory()->create([
'name' => 'Test User',
'email' => 'test@example.com',
]);
}The seeder uses WithoutModelEvents (so creating/created events don't fire during seeding), and creates a single deterministic test user. The commented-out User::factory(10)->create() line is a hint for adding bulk fixtures.
Run with:
php artisan db:seed
# or, fresh DB + seed:
php artisan migrate:fresh --seedDefault connection
config/database.php defaults default to env('DB_CONNECTION', 'sqlite'). The SQLite block:
'sqlite' => [
'driver' => 'sqlite',
'url' => env('DB_URL'),
'database' => env('DB_DATABASE', database_path('database.sqlite')),
'prefix' => '',
'foreign_key_constraints' => env('DB_FOREIGN_KEYS', true),
'busy_timeout' => null,
'journal_mode' => null,
'synchronous' => null,
'transaction_mode' => 'DEFERRED',
],The database/database.sqlite file is gitignored. The composer.json post-create-project-cmd block creates it via touch on a fresh install.
For tests, phpunit.xml overrides DB_CONNECTION=sqlite and DB_DATABASE=:memory: so each test run starts with an empty in-memory database. Tests that need persistence between assertions use Laravel's RefreshDatabase trait.
Adding a migration
php artisan make:migration create_posts_tableThat creates a timestamped file in database/migrations/ extending Migration as an anonymous class. Define up() and down() symmetrically; rerun with:
php artisan migrate # forward
php artisan migrate:rollback # back one batch
php artisan migrate:fresh # drop everything, re-runMigrations are tracked in a migrations table (config/database.php → 'migrations' => ['table' => 'migrations']).
Integration points
config/database.phppicks the connection. Switching from SQLite to MySQL is purely an env-var change.config/cache.php'sdatabasestore,config/session.php'sdatabasedriver, andconfig/queue.php'sdatabaseconnection all point at this same default DB.App\Models\Usermaps to theuserstable.
Entry points for modification
To add a feature that needs storage: write a migration in database/migrations/, add the model to app/Models/, add the factory to database/factories/, and (optionally) seed fixtures from database/seeders/DatabaseSeeder.php. The seeder is the integration point — it calls $this->call(OtherSeeder::class) to chain in dedicated seeders for each feature.
Key source files
| File | Purpose |
|---|---|
database/migrations/0001_01_01_000000_create_users_table.php |
users, password_reset_tokens, sessions |
database/migrations/0001_01_01_000001_create_cache_table.php |
cache, cache_locks |
database/migrations/0001_01_01_000002_create_jobs_table.php |
jobs, job_batches, failed_jobs |
database/factories/UserFactory.php |
Faker-driven User state |
database/seeders/DatabaseSeeder.php |
Creates test@example.com |
See App for the User model and Reference → Data models for a full list of fields and casts.
Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.