Build a CRUD App — Step by StepCore· 40 min read

CRUD Step 1: Plan & Scaffold

Start a complete “Products” feature — the database table, the model and all its routes — with just three commands.

What you will learn

  • Plan a CRUD feature from scratch
  • Create the migration, model and resource controller
  • Understand the 7 RESTful routes Laravel gives you

What we are going to build

Over the next few lessons we will build a small Products manager — a page where you can list, add, edit and delete products. By the end you will have a real, working feature you fully understand. Follow along command-by-command; if you know nothing yet, that is fine — every step is explained.

Each product will have three things: a name, a price, and a description. CRUD apps in Laravel always have the same shape — you create three pieces and Laravel wires the rest:

  1. A migration — the instructions that build the products table in the database.
  2. A model (Product) — the Eloquent class that reads and writes those rows for you.
  3. A resource controller — one class with a ready-made method for each CRUD action.

Step 1 — make the model and its migration together

Artisan (Laravel’s command tool) can make the model and its migration in one go. The -m flag means “also make a migration for it”.

Terminal: create the Product model + a migration
php artisan make:model Product -m

This creates two files: app/Models/Product.php (the model) and a migration in database/migrations/ named like 2026_01_01_000000_create_products_table.php. The migration is where we describe the table’s columns.

Note: Output: INFO Model [app/Models/Product.php] created successfully. INFO Migration [database/migrations/...createproducts_table.php] created successfully.

Describe the columns in the migration

Open that new migration file and fill the up() method — this is the “build the table” instruction:

database/migrations/...createproducts_table.php
public function up(): void
{
    Schema::create('products', function (Blueprint $table) {
        $table->id();                          // auto-increment id (1, 2, 3...)
        $table->string('name');                // short text (the product name)
        $table->decimal('price', 8, 2);        // money: up to 8 digits, 2 after the dot
        $table->text('description')->nullable(); // long text, allowed to be empty
        $table->timestamps();                  // created_at + updated_at columns
    });
}

Line by line: $table->id() makes a unique auto-numbered id; string('name') is a normal text column; decimal('price', 8, 2) stores money safely with two decimal places; text('description')->nullable() is long text that is allowed to be empty (nullable); timestamps() adds the created_at and updated_at columns Laravel manages automatically.

Run the migration

This runs the instruction and actually creates the table in your database:

Terminal: build the table
php artisan migrate

Note: Output: INFO Running migrations. ...createproducts_table .......... DONE The products table now exists with the columns you defined. Check it in phpMyAdmin if you like.

Let the model accept form data (one important line)

Open app/Models/Product.php and add a $fillable list. This tells Laravel which fields are allowed to be filled from a form — a safety feature called mass-assignment protection.

app/Models/Product.php
class Product extends Model
{
    protected $fillable = ['name', 'price', 'description'];
}

Without $fillable, Product::create() refuses to fill the fields (so a hacker cannot sneak in extra columns). With it, only name, price and description can be set from input — exactly the three we want.

Step 2 — make the controller (all 7 methods ready)

Terminal: create a resource controller
php artisan make:controller ProductController --resource

The --resource flag is the magic part: it creates app/Http/Controllers/ProductController.php already containing seven empty methodsindex, create, store, show, edit, update, destroy — one for each CRUD action. We will fill them in the next lessons.

Step 3 — register all the routes with one line

Open routes/web.php and add these two lines:

routes/web.php
use App\Http\Controllers\ProductController;

Route::resource('products', ProductController::class);

That single Route::resource line creates seven routes at once — one for every CRUD action, each pointing at the matching controller method. You did not have to write them one by one.

The 7 routes you just got (learn this table once)

MethodURLController methodWhat it does
GET/productsindex()List all products
GET/products/createcreate()Show the “add new” form
POST/productsstore()Save the new product
GET/products/{id}show()Show one product
GET/products/{id}/editedit()Show the “edit” form
PUT/PATCH/products/{id}update()Save the edits
DELETE/products/{id}destroy()Delete the product

You can see them for real with this command:

Terminal: list the routes
php artisan route:list --name=products

Note: Output (the 7 routes): GET|HEAD products .............. products.index POST products .............. products.store GET|HEAD products/create ....... products.create GET|HEAD products/{product} .... products.show PUT|PATCH products/{product} .... products.update DELETE products/{product} .... products.destroy GET|HEAD products/{product}/edit products.edit

Tip: These 7 routes are identical for every resource — products, posts, users, orders. Learn the table once and building any CRUD becomes a fill-in-the-blanks job. Each route also gets a name (like products.create) you will use to build links.

Q. What does a single Route::resource('products', ProductController::class) line create?

Answer: Route::resource registers all 7 RESTful routes (index, create, store, show, edit, update, destroy), each mapped to its controller method.

✍️ Practice

  1. Scaffold a second resource called Task: run make:model Task -m, add columns, migrate, make:controller TaskController --resource, and add Route::resource.
  2. Run php artisan route:list and find your 7 task routes.

🏠 Homework

  1. Write the 7-route table from memory (method, URL, controller method).
Want to learn this with a mentor?

CodingClave runs guided, project-based training (28-day, 45-day & 6-month batches).

Explore Training →