How to Continuously Deploy a Front-end Project Using GitLab and Surge

I recently built a web project from scratch for a client who had no existing infrastructure for web development. As a believer in continuous integration I decided to go with automated deployment from the very beginning.

After a quick research on off the shelf solutions and came up with the following combination:

The advantage of this setup is the lack of the need for setting up your own server software while both cloud solutions have free plans to start your project with. Moreover GitLab’s free plan includes private repositories.

This blog post will guide you through the first steps of setting up GitLab and Surge for your own web project.


It is assumed you know the basics of Git, have a GitLab account set up and configured with your ssh key and have the following software installed:

Setting up the project

If you don’t have one yet, use your favorite text editor or IDE to create a web project in an empty folder with an index.html at the top level. You can also copy the html, js and css files from the example project I created for this post.

Publishing the project to GitLab

First you will need a local Git repository. Set one up using the commands below:

git init
git add index.html main.css main.html
git commit -m 'First commit'

Next create a new project on GitLab and publish the local repository with these commands (copy the origin URL from GitLab):

git remote add origin
git push -u origin --all

Adding static web hosting

We will use Surge for quick and free static web hosting. It comes with a command line tool that can be installed using npm. Run these commands in the root of the project:

npm init -y # If you don't have a package.json yet
npm install --save-dev surge
node_modules/.bin/surge .

The first time it’s used Surge prompts for an email and password. Choose a subdomain you like or let Surge generate a random one. The output should look like this:

$ node_modules/.bin/surge .

Surge -

          token: *****************
   project path: .
           size: 1 files, 57 bytes
         upload: [====================] 100%, eta: 0.0s
propagate on CDN: [====================] 100%
           plan: Free
     IP Address:

Success! Project is published and running at

Open in your browser to see the published web project.

Important: Surge prompts for a subdomain every time you run it, if you want to stick with one, save it with the project:

echo > CNAME

This is the right moment to make a Git commit:

echo node_modules >> .gitignore # Avoid commiting Node.js dependencies
git add CNAME package.json package-lock.json .gitignore
git commit -m 'Added Surge static hosting'

Setting up continuous deployment

GitLab’s continuous integration pipeline can be configured with .gitlab-ci.yml placed in the root folder of the project. Create one with the following content:

image: node

  - npm install

  stage: deploy
    - node_modules/.bin/surge .

Before pushing .gitlab-ci.yml to GitLab the pipeline has to be configured with Surge access credentials so that it can publish to the domain you configured in the previous step. First obtain a token from Surge:

$ node_modules/.bin/surge token

    Surge -

              token: *****************
              token: <COPY THE TOKEN FROM HERE>

Next go to GitLab -> Your project -> Settings -> CI / CD -> Secret variables

And now commit and push .gitlab-ci.yml to GitLab. In a short while you should see the pipeline running under GitLab -> Your project -> CI / CD -> Pipelines. If it fails click on the red failed pipeline and the failed job to see the full terminal output of the deploy job for troubleshooting.

From now on every change you push to GitLab will automatically be deployed to Surge.

Bundling the project

No serious front-end project can get away without a bundling tool nowadays. To keep things simple I used AssetGraph-builder. This tool has the advantage of taking care of bundling JavaScript, CSS and HTML files by using an HTML file as an entry point with zero configuration - perfect for a newly created simple web application.

Setting up AssetGraph-builder is not more complicated than running these two commands:

npm install --save-dev assetgraph-builder
node_modules/.bin/buildProduction --outroot=dist index.html

Check the contents of dist folder to see the bundled project.

To do the bundling automatically on GitLab, tweak the contents of .gitlab-ci.yml:

image: node

  - npm install

  stage: deploy
    - node_modules/.bin/buildProduction --outroot=dist index.html
    - cp CNAME dist/
    - node_modules/.bin/surge dist

Commit and push all changes to GitLab to run the pipeline. Don’t forget to add dist folder to .gitignore. After a short while the bundled project should be republished to Surge.

Next steps

It should be easy to adopt this approach to your favorite front-end toolchain. Using Yarn instead of npm or bundling with Webpack or Browserify is not much different from the tools used here.

A decent software project has automated tests. Fortunately we already have a pipeline set up with the potential of running our tests. Read the GitLab CI documentation on how to set up advanced pipelines with multiple jobs and stages.

The examples above are published to a GitLab project including public access to the pipeline.


If your project is actually a static web site without the need for a sophisticated bundling process or automated tests a static site generator and/or GitLab Pages or GitHub Pages would do the job.

There are also alternatives for continuous integration, Travis CI for example is free for public projects.