Bootstrapping a Laravel CRUD Project

By Nick Salloum

Working with PHP 7.1? Download our FREE PHP 7.1 Cheat Sheet!

How to Build a Basic Laravel CRUD App

In this tutorial, we’re going to build and run a simple CRUD application from scratch using Laravel 5.

Laravel Logo

Installation and Setup

If you’re already deep in PHP, then some of the stuff in this section will be common knowledge to you. In any case, let’s go over it. We create a fresh install of Laravel 5 using Composer. First, cd into your directory of choice. Now, run the following command:

composer create-project laravel/laravel MYPROJECT

If you don’t have Composer installed, you’ll naturally need to do that first, but I recommend using an environment such as Homestead Improved for kickstarting your development flow anyway – it comes with Composer globally preinstalled.

The name “MYPROJECT” will be the name of your application directory. For this tutorial, I just called mine “crud”.

First Launch and Database Configuration

Let’s sort out the database.

If you’re unfamiliar with environment files, I suggest you give them a read here. It’ll help you in the future when you’re ready to push out a production-level application that warrants a more powerful database. For now though, we’ll just use SQLite – a file-based, zero-configuration database engine. Out of the box, there’s nothing to configure which makes it easy for test applications like this one.

Navigate to the config directory, and open up the database.php file. Change the default database connection setting to sqlite, and we’re almost ready to rock and roll. Scroll down a bit further in that file, and you’ll see the actual database connections. You’ll notice that SQLite leverages a database.sqlite file that’s kept in the storage directory in the root (accessible by storage_path()). We don’t have this file yet, so let’s create it quickly in the command line:

touch storage/database.sqlite

Make sure the storage folder is writable by the web server. If you’re using our Homestead Improved box, this is taken care of for you.

Our database is now set up, and we’re ready to run some CRUD operations. But first, let’s take a look at routing in Laravel, as well as some Blade syntax and setting up a basic template.

A Quick Note On The Artisan CLI

Artisan is Laravel’s built-in command line interface. It allows us to interact very nicely with our app during development. It ships with a host of commands that lets us create models, controllers, database migrations, and even perform manual CRUD operations. To see a list of commands, run php artisan in the command line. I’ll be using the artisan command quite a bit from here on, so read up on the docs to familiarize yourself with it.

Resourceful Routing

Inside the app/Http directory, you’ll find a file there called routes.php. The routes file defines the majority of the routes in your application. By default, there’s some routes already defined. Let’s delete all of them though, and start from scratch. For this tutorial, let’s run our CRUD operations on a simple task list. We’re going to need two main routes for our app:

  • A home page route – one that just displays a generic home page
  • Our task route, which will be the basis for the RESTful structure for the CRUD operations to be performed.

At this point, I suggest you read up on routing in Laravel 5. I’ll be using named routes, as well as controller actions to govern the output. For our home page, we’ll just use a basic GET route:

Route::get('/', [
    'as' => 'home',
    'uses' => 'PagesController@home'

Notice I’m using a PagesController which we don’t have yet. Don’t worry, we’ll create that soon using artisan. Before we jump ahead though, it’s time to read up on RESTful resource controllers, and their painless generation via the artisan command line interface. We can register a resourceful route to a controller like this:

Route::resource('tasks', 'TasksController');

According to Laravel:

This single route declaration creates multiple routes to handle a variety of RESTful actions on the resource.

With all that in mind, we can now create our two controllers via the command line:

php artisan make:controller PagesController
php artisan make:controller TasksController

Let’s first open up the PagesController. Navigate to app/Http/Controllers/PagesController, and take a look at the file. You’ll notice that artisan generated a bunch of methods for us that would be useful for RESTful actions. We’ll keep these for our TasksController, but for our PagesController, we’ll just want one method for now – home. Delete all the methods, and create the home method:

public function home()
    return 'Welcome home!';

Refresh the home page in your browser, and we’re home! By now, you’re probably excited to get into the good stuff, but let’s first talk about views, pull in a couple of assets, and make a basic template so our app looks pretty.

Just as a quick aside, if you want to create a controller using the artisan CLI, and you want it to have no methods be default, you can add the --plain flag to the command like this:

php artisan make:controller YourController --plain

Alright, moving on.

Views & Basic Templating With Blade

So far, we’ve set up some routes and returned a meaningless string to the screen. It’s not much, but it’s a start. Instead of returning a string though, let’s return a view. Views serve up the front-end of your application. Think of them as purely presentational. We want our views to only ever serve up data that’s already been passed to them, and we’ll see how to pass data to a view a bit later. Inside the /resources directory, you’ll see a directory called “views”. Here’s where we keep our views, and here’s also where we’re able to reference them from. Let’s do a couple of things here:

  1. Let’s create a sub-directory called pages, and in it, create a new file called home.blade.php.
  2. Let’s create another sub-directory called layouts, and in it, create a new file called master.blade.php.

As you’d expect, we’ll want to have some kind of master layout so that we don’t have to repeat big chunks of HTML. Different pages in our app will then reference the master layout view, and inject content into dedicated sections. We’ll pull in bootstrap for CSS convenience, and draw up a basic HTML file:

<!doctype html>
<html lang="en">
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="">

<nav class="navbar navbar-default">
  <div class="container-fluid">
    <div class="navbar-header">
      <a class="navbar-brand" href="#">Tasks</a>
    <div class="nav navbar-nav navbar-right">
        <li><a href="#">Home</a></li>
        <li><a href="#">Tasks</a></li>

    <div class="container">


In particular, notice the @yield('content') part of this file. This will allow us to reference a content section in any template pages, and inject whatever content you want in there. In our home.blade.php file, we can now have something like this:



<h1>Welcome Home</h1>
<p class="lead">Lorem ipsum dolor sit amet, consectetur adipisicing elit. Maiores, possimus, ullam? Deleniti dicta eaque facere, facilis in inventore mollitia officiis porro totam voluptatibus! Adipisci autem cumque enim explicabo, iusto sequi.</p>

<a href="{{ route('tasks.index') }}" class="btn btn-info">View Tasks</a>
<a href="{{ route('tasks.create') }}" class="btn btn-primary">Add New Task</a>


We’re extending the master layout, and inserting into the content section. As you can see, blade syntax makes this stuff a breeze. We’re going to move on a bit, but you can read up more on blade syntax and templating here.

Back in our PagesController, we can now return a view to the home page. If you read the documentation on views, you’ll know it’s as easy as this:

public function home()
    return view('pages.home');

Refresh your browser, and there you go!

Home page view

Let’s head over to our TasksController now. This time, we’ll keep the methods that were automatically generated via the artisan command line, and here’s why:

  1. They are already named in a RESTful way for us.
  2. The routes are already connected to the respective methods because of Laravel’s resourceful routing.

If we navigate to /tasks, we’ll see a blank page. That’s because our app is using the index method, and we have nothing in it yet. Just by simple logical deduction, we can figure out what each of the other methods should be responsible for to fit in line with a RESTful structure:

  • create will be the method we use to generate a page where we can create new tasks
  • store will be the method we use to handle POST data from the task creation, and store it in the database
  • show will be the method used to show a single task
  • edit will be the method used to allow us to edit an existing task
  • update will be the method that gets called for updating an existing task
  • destroy will be the method used to destroy – or delete – a task

For now, let’s just focus on our index method. In the views directory, I’m going to create a new file under tasks/index.blade.php, and pull in the layout like last time. Here’s the template I have:



<h1>Task List</h1>
<p class="lead">Here's a list of all your tasks. <a href="/tasks/create">Add a new one?</a></p>


Here’s a screenshot of the progress.

Tasks page default view

At this point, I want you to notice that I’ve hard-coded the link to create a task. If you’ve been reading the documentation links I mentioned earlier, you’ll be familiar with named routes by now. Resourceful routing automatically names our routes for us, and you can see them all in the artisan command line:

php artisan route:list

Now, we can link to the create route in our blade templates like this:

<a href="{{ route('tasks.create') }}">Add a new one?</a>

Let’s update our navigation also, so we can easily click through:

<nav class="navbar navbar-default">
  <div class="container-fluid">
    <div class="navbar-header">
      <a class="navbar-brand" href="{{ route('home') }}">Tasks</a>
    <div class="nav navbar-nav navbar-right">
        <li><a href="{{ route('home') }}">Home</a></li>
        <li><a href="{{ route('tasks.index') }}">Tasks</a></li>

Alright, our app is coming together. We’re ready to start adding tasks and building up our create method and view, but we’re not quite there yet. We want our tasks to store to the database, but we haven’t set up a table yet. Luckily, Laravel makes table creation and maintenance a breeze. Let’s dig in.

Database Migrations

Let’s head over to the migrations documentation and give it a read.

Migrations are a type of version control for your database. They allow a team to modify the database schema and stay up to date on the current schema state.

Creating a migration is easy with artisan. Here’s what we’ll do to create our tasks table migration:

php artisan make:migration create_tasks_table

There are two additional options that we can use in our migration command:

  • --create – lets artisan know that we want our migration to actually create the table
  • --table – lets artisan know which table we want our migration to reference

In our case, we’re creating the table for the first time, so our artisan command should look like this:

php artisan make:migration create_tasks_table --create=tasks

Navigate to the newly generated migration – it will be in the /database/migrations directory. Running a migrate command will instruct Laravel to look inside this directory, and follow any database migrations that haven’t happened yet. Each migration has two functions:

  • up – this is run when the migrate command is called
  • down – this is run when a migration is rolled back

In our case, our up function will create the tasks table with the necessary fields, and the down command will drop it. We’ll probably want our tasks to have a title and description too, so let’s add those in. Here’s what our up function should look like now:

public function up()
    Schema::create('tasks', function(Blueprint $table)

Now, let’s run our migration to get our database set up:

php artisan migrate

Now we have our tasks table. We’re using SQLite, so let’s make sure of that via the command line. Run the following two commands:

sqlite3 storage/database.sqlite

The first launches an SQLite command line interface, and the second outputs our tables. If your migration was successful, you should see tasks listed. We’re now ready to perform our CRUD operations.

Models & Eloquent ORM

Now that our database is set up, it’s time to talk about Eloquent Models and Laravel’s Eloquent ORM. Head over to the documentation, and in particular, take note of this:

The Eloquent ORM included with Laravel provides a beautiful, simple ActiveRecord implementation for working with your database. Each database table has a corresponding “Model” which is used to interact with that table.

Basically, think of a model as a representation of a database table, via which we can perform database operations. Let’s create our Task model:

php artisan make:model Task

By default, we don’t need to specify which table we want to interact with. Laravel will read Task and automatically fetch the tasks table. To use a custom table, just specify it like this in the Model class:

protected $table = 'custom_tasks';

Now, by referencing the model from inside our controller, we can use Eloquent to interact with the database.


In this part, we’ve bootstrapped our Laravel CRUD application by creating the database, some controllers, basic routes and simple views. In the second part, we’ll implement all the CRUD functionality we prepared the foundations for in this post.

  • Nouar TALBI

    It ‘s all what you want to make ?

    • In part 2, we’ll assess the actual creating, reading, editing, and deleting of content, fulfilling the whole CRUD aspect. Stay tuned, it releases on the 22nd!

  • Matt B

    Where you have “Here’s a screenshot of the progress.” – the current layout does not look like this. I think it’s because you haven’t detailed how to change the index() function in the TasksController (I’m guessing it should look something like the following:

    public function index()
    return view(‘tasks.index’);

    • You are right. The index() method in the Tasks controller should indeed return tasks.index just as you mentioned, `return view(‘tasks.index’)`. Slight oversight on my part, I’ll get it to the editor!

      • Matt B

        Great – and looking forward to a part 2(?) on create tasks!?

        • It should be coming up today (22nd May), look out for it!

          • V Arun Kumar

            i cant see part 2

      • Raed667

        is returning a 404

        I have created both /views/pages and /views/tasks

        • Deepu

          Did you fix the error?

        • Deepu

          Got Fixed! You must turn on

          LoadModule rewrite_module modules/

          in Apache httpd.conf

  • Very nice tutorial. Easy to understand, easy to follow!

    I call “http://localhost:8080/tasks”

    And get:
    FatalErrorException in TasksController.php line 39:Class ‘AppHttpControllersTask’ not found
    in TasksController.php line 39

    public function store(Request $request)
    $input = $request->all();
    Task::create($input); // Line 39
    return redirect()->back();

    How to solve that?

  • Sathit Chaiwiwattrakul

    When create Task Model, It automatic add migration, So should we do migration after create Model? Otherwise, we have to delete the additional migration in this step.

    C:project_laravelMYPROJECT>php artisan make:model Task

    Model created successfully.

    Created Migration: 2015_05_26_220005_create_tasks_table

    • webmachine

      I’d be very interested in the answer to this question. I noticed the extra migration and just deleted it, but is it there for a reason?

      • Sathit Chaiwiwattrakul

        I think this is new feature in Laravel 5 to automatic create migration when we create model because model must reference to table in database. So we don’t need to create separate migration.(This should come from Laravel 4).

        But I don’t know which case we should manual create migration?
        Wait answer again.

        • This may be a feature update since I wrote the tutorial, although I am using laravel 5. Maybe it’s a new feature.

  • Melissa

    Hi,I’m using win 8 and when I type touch storage/database.sqlite it says touch is not recognize as an internal or external command. Could someone help me, please

    • Jack Hannigan Popp

      Touch is a unix command so won’t work on windows 8.

      try – copy NUL storagedatabase.sqlite

      Also I’d recommend you checking out homestead (vagrant) this will give you a virtual unix environment on your windows machine, which will probably help a fair bit since most tutorials have been written for unix environments.

      • Melissa

        Thank you :))

  • Max Penderuk

    Awesome tutorial dude !) I followed all these steps and my app is working. But I wanna try Doctrine2 instead of Laravel Database Migrations :) What do u think about this ? What’s better ? Just I don’t know about Laravel Database Migrations and Doctrine2 seemed pretty easy to me.

  • Glenn Timoteo

    I’m in the part of displaying the index of tasks

    >> http://localhost/test_crud/tasks

    >> getting error 404 Not Found
    >> i put the return view(‘tasks,index’); in index() of TasksController

    I wonder what i missed… Please help. Thanks

    By the way, where do i put this code,
    Route:resource(‘tasks’, TasksController);
    is it in route.php?

  • Glenn Timoteo

    im getting 404 not found error message on localhost/test_crud/tasks


    Route [tasks.index] not defined. (View: C:xampphtdocsdemoresourcesviewspageshome.blade.php)



  • Val Luminarias

    in home.blade.php, it should be @extend(‘pages.layouts.master’);

  • Mukesh Mishra

    php artisan make:controller is creating only controller without method.
    I want to create controller with basic methods.

  • Ghostmech

    I am late to the party, but some of these things don’t go as planned:

    To get Laravel 5.2.31 to recognize the database.sqlite file, I had to modify the database.php file (‘sqlite’ SECTION) to read:
    ‘database’ => ‘__DIR__ . ‘/../database/database.sqlite’,
    and finally Laravel complied, otherwise it generates a ‘could not open’ error.

    Also, he left out in this tutorial that BEFORE you can get “root”/tasks to show a page,
    you have to open TasksController.php and INSIDE the index() function add:

    return view(‘tasks.index’);

    or else you will still be scratching your head and looking at a blank page, or at least I DID.

    Hope this helps!

  • Rouhollah Mazarei

    I think there should be “by default” :
    … and you want it to have no methods “be default”, you can add the …

  • Ghostmech

    Please put a LINK to part two in this article. It’s VERY annoying trying to search for it, and I believe that others would feel the same.

Get the latest in PHP, once a week, for free.