DEV Community

Cover image for Deploying your Laravel + MySQL application on Heroku
Douglas Pinheiro Goulart
Douglas Pinheiro Goulart

Posted on • Edited on

Deploying your Laravel + MySQL application on Heroku

Introduction

So, you've just built your beautiful Laravel application, it has authentication, localization, tests and all the fancy features that could possibly impress the recruiter and land you a job. However, it's only working on your machine. How do we solve this?

In this post, we’ll be looking into hosting a Laravel application (with a MySQL or MariaDB database included) on Heroku for free.

Deploying

💡 Notice: Replace items within brackets ([]) with your desired information.

Creating Laravel application

If you don't have a Laravel app yet, the first thing we got to do is create a brand new one. To do this, first you need to have Composer installed on your machine. After installing composer you can run the following command to install the Laravel installer:

composer global require laravel/installer
Enter fullscreen mode Exit fullscreen mode

And then you can create a new Laravel app:

laravel new [brand-new-app]
Enter fullscreen mode Exit fullscreen mode

For more information about Laravel installation, check the Laravel Installation guide. It’s worth a read before following the instructions in this article.

Initializing git

To deploy to Heroku we'll be using Git. If you don't know how to use this, I recommend you watch the Git and GitHub Crash Course on freeCodeCamp. It's a very important tool for developers and you should know it.

Anyways, the first thing you gotta do is enter your project folder using the terminal and initialize a git repository:

git init
Enter fullscreen mode Exit fullscreen mode

And then adding all the files and making a commit

git add .
git commit -m "Initial commit"
Enter fullscreen mode Exit fullscreen mode

Alright, now your git repository is set.

Using the Heroku CLI

We'll use the Heroku CLI to deploy our app. You can find the installation guide here.

After you've installed the Heroku CLI, create a Heroku free account and run heroku login in your terminal. Follow the instructions and after you've been successfully logged in, you can create your Heroku application (change brand-new-app to your desired app name):

heroku create [brand-new-app]
Enter fullscreen mode Exit fullscreen mode

Now you need to generate the APP_KEY required by Laravel. You can do this by using the heroku config:set APP_KEY=$(php artisan --no-ansi key:generate --show) command.

Creating a Procfile

By default, Heroku will launch an Apache web server together with PHP to serve applications from the root directory of the project.

However, our application’s document root is the public/ subdirectory, so we need to create a Procfile that configures the correct document root. We can do this by manually creating a Procfile file or using the terminal:

echo "web: vendor/bin/heroku-php-apache2 public/" > Procfile
Enter fullscreen mode Exit fullscreen mode

Add the untracked files and commit your changes:

git add .
git commit -m "Procfile for Heroku"
Enter fullscreen mode Exit fullscreen mode

Pushing to Heroku

Now you should be able to push your app to Heroku:

git push heroku master
Enter fullscreen mode Exit fullscreen mode

To view your app, access https://[brand-new-app].herokuapp.com or click the Open app button located in the Heroku dashboard (https://dashboard.heroku.com/apps/[brand-new-app])

Avoiding Mixed Content error

If you use the asset() helper function a lot, you'll probably notice that your hosted app isn't loading some assets files and is showing a Mixed Content error in the console.

Mixed Content Error

To fix this, open your applications' AppServiceProvider at [brand-new-app]/app/Provider/AppServiceProvider.php and, in the boot() method, add:

if (config('app.env') === 'production') {
    \URL::forceScheme('https');
}
Enter fullscreen mode Exit fullscreen mode

And now create a APP_ENV variable with a production value using the Heroku CLI or on your app's settings (https://dashboard.heroku.com/apps/[brand-new-app]/settings > Config Vars > Reveal Config Vars).

heroku config:set APP_ENV="production"
Enter fullscreen mode Exit fullscreen mode

Commit and push your new changes to Heroku

git commit -am "Adding URL::forceScheme('https') in production environments"
Enter fullscreen mode Exit fullscreen mode

Now your project should load properly without errors

Assets loaded with no errors

If the error persist, check if there are no links using HTTP instead of HTTPS.

Setting environment variables

The next thing we need to do is set our .env variables in Heroku. We've already set the APP_ENV and APP_KEY variables, let's set the remaining ones. Again, you can do this by using the Heroku CLI or on your app's settings (https://dashboard.heroku.com/apps/[brand-new-app]/settings > Config Vars > Reveal Config Vars).

Config vars

You can keep the database information (DB_CONNECTION, DB_DATABASE, DB_USERNAME, etc) the same as the local configuration for know. We'll take care of that later.

Adding and configuring database

Now we have to add a database to our project.

Go to your application dashboard and click on resources (https://dashboard.heroku.com/apps/[brand-new-app]/resources). In the "Add-ons" input, type MySQL and choose ClearDB MySQL. Select the "Ignite - Free" plan and click on "Submit Order Form".

Make sure you assigned your credit card to your Heroku account. If you didn't add it yet, click on your profile photo (top right corner) > Account settings > Billing > Add credit card. Don't worry, you won't be charged unless you choose a paid plan. As soon as you've added your card, repeat the step above.

As soon as you've added the ClearDB MySQL add-on, go to your terminal and type heroku config | grep CLEARDB_DATABASE_URL

It should display something like this:

CLEARDB_DATABASE_URL:  mysql://uuuuuuuuuuuuuu:pppppppp@hh-hhhh-hhhh-hh.cleardb.com/heroku_ddddddddddddddd?reconnect=true
Enter fullscreen mode Exit fullscreen mode

Everything after the @ symbol until the / is the DB_HOST (hh-hhhh-hhhh-hh.cleardb.com). Everything after / until ? is DB_DATABASE (heroku_ddddddddddddddd). The string after the // until : is the DB_USERNAME (uuuuuuuuuuuuuu). The string between : and @ is the DB_PASSWORD (pppppppp).

Don't show, tell or publish these credentials anywhere. These are your database information. That's why I censored it. In your case it should have real numbers and letters.

Now it's time to change your production database environment variables with the real ones provided by ClearDB. Go to your app settings (https://dashboard.heroku.com/apps/[brand-new-app]/settings), click "Reveal Config Vars" and change the database variables. It should be like this:

key value
DB_HOST hh-hhhh-hhhh-hh.cleardb.com
DB_DATABASE heroku_ddddddddddddddd
DB_USERNAME uuuuuuuuuuuuuu
DB_PASSWORD pppppppp

Migrating database tables

Now it's time to run our migrations and create our database tables.

In your terminal, type heroku run php artisan migrate:fresh. It will ask you if you really want to run this command, type yes.

After running this command, there is a high chance that it will return this error:

Migrations error

It happens because, by default, Laravel uses the utf8mb4 character set. If the server is running a version of MySQL older than the 5.7.7 release or MariaDB older than the 10.2.2 release, you may need to manually configure the default string length generated by migrations.

Learn more at: https://laravel.com/docs/8.x/migrations#index-lengths-mysql-mariadb.

To fix this, add the code below to the boot() method located in your app/Providers/AppServiceProvider.php

Schema::defaultStringLength(191);
Enter fullscreen mode Exit fullscreen mode

Don't forget to import Schema at the top of the file:

use Illuminate\Support\Facades\Schema;
Enter fullscreen mode Exit fullscreen mode

Your AppServiceProvider should be like this at this point:

<?php

namespace App\Providers;

use Illuminate\Support\ServiceProvider;
use Illuminate\Support\Facades\Schema;

class AppServiceProvider extends ServiceProvider
{
    /**
     * Register any application services.
     *
     * @return void
     */
    public function register()
    {
        //
    }

    /**
     * Bootstrap any application services.
     *
     * @return void
     */
    public function boot()
    {
        if (config('app.env') === 'production') {
            \URL::forceScheme('https');
        }

        Schema::defaultStringLength(191);
    }
}
Enter fullscreen mode Exit fullscreen mode

Commit your changes and push to Heroku again

git commit -am "Setting defaultStringLength to 191"
git push heroku master
Enter fullscreen mode Exit fullscreen mode

Run the migrations again with heroku run php artisan migrate:fresh and it should work.

Seeding the database

Let's learn how you can seed your database in case you need to.

In your terminal, type heroku run php artisan db:seed. It will also ask you if you really want to run this command, type yes.

💡 Notice: Heroku increments tables by 10, for example id's would appear like this: 1, 11, 21, 31. Beware when using user IDs for reference in Seeds or Factories.

When you run this command, it might tell you that the Class 'Faker\Factory' was not found. It happens because faker is required as a dev dependency. To fix this, simply open your composer.json file and move "fzaninotto/faker": "^1.9.1", from require-dev to require.

And then run composer update.

Moving faker from

Commit your changes and push to Heroku one more time

git commit -am "Moving fzaninotto/faker from require-dev to require in composer.json"
git push heroku master
Enter fullscreen mode Exit fullscreen mode

Seed the database again with heroku run php artisan db:seed and it should work.

[BONUS] Storing uploaded files

In case you are working with file uploads in your Laravel application, there's one caveat you should be aware of: Heroku uses ephemeral filesystem. That means that any changes to the filesystem whilst the dyno is running only last until that dyno is shut down or restarted. Each dyno boots with a clean copy of the filesystem from the most recent deploy. In addition, under normal operations dynos will restart every day in a process known as "Cycling".

When this happens, your image or any other uploaded file will be completely deleted from your application and users will see nothing but the image alt text.

Knowing this, it's recommended that you use a dedicated file storage service such as AWS S3.

You can learn more about this approach that Heroku uses here and here.

Conclusion

Congratulations! Now you have your Laravel application up and running. Now you can add it to your portfolio and show your work to people.

Heroku free plan has some limitations and maybe your app stop working in some days of the month (it usually goes back online when a new month starts). If you are feeling the need to upgrade, do it.

Improvements and/or corrections are welcome 😀.

Further reading

Top comments (8)

Collapse
 
eduardonwa profile image
Eduardo Cookie Lifter

Bro, i think this is one of the BEST laravels tutorials I have ever found on this site. Thank you, however I have a question regarding the faker, I get a "fakerphp/faker": "^1.9.1" instead of "fzaninotto/faker": "^1.9.1", is this the same thing but maybe you have another kind of faker??

Collapse
 
doougui profile image
Douglas Pinheiro Goulart • Edited

I just saw that fakerphp/faker is really a fork of the archived fzaninotto/faker repository, as I suspected.

faker github repository

Collapse
 
doougui profile image
Douglas Pinheiro Goulart

Oops, sorry for the wait, I did not see your comment. So, looking at the official "fzaninotto/faker" GitHub repository, it seems like the project was archived. The creator has written a blog post about this. You can check it out here: marmelab.com/blog/2020/10/21/sunse...

Collapse
 
benjajorquera profile image
Benja Jorquera

Nice guide! Thank you! I was able to deploy my calendar appointments api. Here some tips:

  1. grep in Windows: findstr
  2. Be careful if you are working with date and time data types in your DB
  3. If you get an error with the server, change the APP_DEBUG to true in your Config Vars to see what happens.

Cheers!

Collapse
 
doougui profile image
Douglas Pinheiro Goulart

Nice! Thank you for the tips :)

Collapse
 
laysanha profile image
Laysa Santiago

Topp dms

Collapse
 
theowlsden profile image
Shaquil Maria

Great and clear walkthrough!
Will use this guide to deploy my app once it's tested.

Keep it up!🤙🤙

Collapse
 
doougui profile image
Douglas Pinheiro Goulart

Thank you 😀.

I'll keep updating the article if needed. Feel free to suggest improvements if I've forgotten anything.