Building Static Sites with Middleman

When all you have is the hammer of Rails, everything looks like a database backed dynamic site. But often we'd be much better served by a simple static site, and Middleman is a great choice for building these static sites. Join Chris as he shows off some of the more advanced tips and techniques you can use to efficiently build and deploy your next static site.

This is a companion discussion topic for the original entry at

Excellent weekly iteration on building static websites with Middleman. I’m already using Middleman for my static websites now, but I learned a ton in this weekly iteration, like the use of partials and some performance tweaks. I could put them immediately to practice in my own projects.

I would love to see more videos like this, for instance on the use of Thoughtbot’s Sass libraries Bourbon, Neat and Bitters. Handy tips that can be implemented right a way in your own projects.



Thanks for this weeks episode Chris. The preparation really shone through. Middleman is Ace. I’ve used it for personal sites & for UX projects where we have built out the front end of complex apps where using partials for template areas & ruby to fill in 60x rows of data etc is really handy.

Sometimes I wish there was just a bit of dynamic behaviour available like something like Statamic, which enables more functionality & a control panel to manage data etc. but of course then it wouldn’t be static html. (statamic runs on php)

Hey @acandael & @asecondwill, thanks for the kind words and glad you enjoyed the episode.

@acandael we do have an overview video that introduces Bourbon, Neat, Bitters, etc: I think we could easily go deeper on each of the topics, but something to take a look at it you’re interested in that particular topic.

Also, someone asked in the support email what the git magic I was using to walk through the commits, so thought I’d share that:

  # in the [alias] section of my ~/.gitconfig file
  next-commit = !git checkout $(git log --reverse --ancestry-path --pretty=%H HEAD..master | head -1)

With that alias in place, I can check out any parent commit (the root commit in this case, via root = rev-list --max-parents=0 HEAD) and then use git next-commit to walk up the commits on master.


Thanks for the episode this week!

I’m in the process of converting an old site with .htm extensions. I would like to convert to clean urls (no extensions) if possible. Is there a good way to set up the site to respond to .htm, .html, and / ?

Glad you enjoyed it @kcantwel.

I think you would want to set up redirects from the old .htm (and .html) URLs, to the new clean URLs. Assuming you’re using S3 to serve the app, then middleman-s3_redirect looks like a great option. Other servers will have a similar configuration I’d guess.

Yeah! thanx for the tip! That would be awesome if you guys make some advance level GIT tips & tricks for the future shows. I’d loved that :slight_smile:

Thanks @christoomey. I will try that approach.

@christoomey yeah I would love to see a video that goes deeper on Bourbon, Neat (and Bitters). Something in the vein of what you did for the Middleman video: step by step building a website.




Hey Chris or anyone,

4 challenges so far, 4 resolved, YAY.

Challenge 1 (resolved)
Never used bourbon or neat prior to following this tutorial, ie none of the gems installed anywhere. I ran into an issue with @import grid-settings. Basically it said it could not import grid-settings. I don’t know if this is true or not, but it appears that grid-settings relies upon bitters. When I added gem bitters to my Gemfile it resolved the error. However, I then got a global variable $golden. missing error. When I bumped @import grid-settings below my @import bourbon that error was also resolved. But my grid system is still not functional. I’m struggling to understand how you get a 3 column grid output on locations when you have the line @include span-columns(4). That to me says a 4 column grid. I must be missing something.

^^^ I’ve resolved Challenge 1
Challenge 1 Fix
I changed the unworking grid system by changing…

&:nth-child(3n) {
  @include omega;


@include omega(3n);

Challenge 2 (resolved)
Another question about the bash script. So in the directory with all my files I ran the following commands

$ mkdir bin
$ vim bin/deploy

then within there I copied and pasted the following code


set -e

bundle exec middleman build --clean
bundle exec middleman s3_sync

I then ran your command

$ bin/deploy
=> -bash: bin/deploy: Permission denied
$ sudo bin/deploy
=> sudo: bin/deploy: command not found

$ cat bin/deploy

set -e

bundle exec middleman build --clean
bundle exec middleman s3_sync

I’m stumped as usual.

Solution to Challenge 2
from the root directory of the project
run $ chmod +x bin/deploy

That will give your bash command executable rights which allows you to run it like a boss.

Challenge 3 (resolved)
I’m getting an error when deploying to S3. Since I can’t get the bin script to work, I just ran it manually. The first command works fine, but the 2nd one not so much.

$ bundle exec middleman s3_sync
 => You need to activate the s3_sync extension and at least provide the bucket name.

I’m assuming it’s mad about my config.rb file. So I popped that sucka open and I had…

activate :s3_sync

And I thought hmm, they don’t know the bucket. So many I should add more stuff to make the programming lords happy.

activate :s3_sync do |s3_sync|
  s3_sync.bucket                     = ENV['AWS_BUCKET']
  s3_sync.aws_access_key_id          = ENV['AWS_ACCESS_KEY_ID']
  s3_sync.aws_secret_access_key      = ENV['AWS_SECRET_ACCESS_KEY']

Same error, turns out the programming gods are hard to please.

Challenge 3 FIX -> change .sample.env to .env

Challenge 4 (resolved)

Since the release of this video fog-core came out with a new version v1.35.0. That update blows up s3_sync.

$ bundle exec middleman s3_sync
     s3_sync  Let's see if there's work to be done...
     s3_sync  Ready to apply updates to fuckaws.
     s3_sync  Creating index.html
/Users/theDanOtto/.rvm/gems/ruby-2.1.2/gems/fog-core-1.35.0/lib/fog/storage.rb:68:in `get_content_type': uninitialized constant Fog::Storage::MIME (NameError)

fix it by adding
gem "fog-core", "1.34.0"
to your Gemfile. Then running $ bundle update fog-core

I had the same issue. Thanks for the tip!

Hi @thedanotto, thanks for sharing all of these. I (and the rest of Upcase!) really appreciate you sharing both your questions and your questions that you resolved. Super useful.

As for #2, I believe the missing piece is you need to mark the script as executable. chmod +x bin/deploy should work for you. Also, keep your eyes out for the next weekly iteration episode as it will be very topical to this conversation :wink:

1 Like

Of course! And you nailed it. Looking forward to the next Weekly Iteration, as always.

Happy to report we now have a much more complete answer to the question re: bin/setup and command line scripts in the form of the most recent Weekly Iteration episode, Let’s Build a CLI.

Hey @christoomey, it appears that some of the middleman-blog features and middleman-s3_sync do not play perfectly. middleman-s3_sync will ignore some files and folders created by middleman-blog and therefore not upload them to s3. The specific folders and files have to do with tags folders and year folders which categorize posts. However, those files and folders do end up in my build folder after running bundle exec middleman build --clean.

Did you have any suggestions on getting those files to properly sync? Or any ideas on helping s3_sync recognize that those files/folders need to be uploaded?

I opened an issue on github.

Oh yea, if I manually upload the files, s3_sync will delete them. Foiled again!

I don’t have any pointers on the particular issue, although it seems like there might be some issues with the newer versions of some of the gems.

You can see the versions used in the video (in particular S3_sync) in the Gemfile.lock

What were the reasons that you guys decided to host the Thoughtbot middleman blog on Heroku?

The thoughtbot blog has actually gone through a dizzying array of different implementations. I first worked with it as a tumblr blog, then we ported to middleman, then we moved to Rails. The final move to Rails was primarily to allow for scheduling posts to publish at specific times.

Nice video!
What would you recommend for a landing page/welcome page of fully blow rails app. As I can see upcase repo uses rails directly, would it be good idea to use middleman for landing page and then redirect user to rails app on login/sign up ?
Do you have any experience with using middle man inside rails app ?

Hey @dixpac, thanks for the kind words! To your question, I think it is a matter of preference but I personally prefer the simplicity of having everything together in one Rails app rather than splitting into two apps and either proxying requests, or hosting middleman within the Rails app.

That said, if we just need to accept a small amount of user input (a contact form or similar), then FormKeep can help power up a Middleman app. Coming from the other side, if working in Rails and you need a number of mostly static pages (landing pages, marketing page, etc) then High Voltage can help make it easy to add these static pages.