Cartography With TileMill

tilemill logo

TileMill is a rugged application for designing detailed, beautiful maps. It is not meant for editing data or conducting analysis, but rather for cartography. With TileMill you use:

  • data (this could be your OpenStreetMap database, or shapefiles)
  • icons (you can use existing icons or design your own)

TileMill provides a platform in which you can style your data in an elegant way and apply your own icons. You can then export your map as an image or in the MBTiles format, which can be hosted on MapBox and placed on your website as an interactive map.

In this chapter we will go through:

  1. Installing TileMill
  2. Exploring TileMill (Map, Legend, Teaser, CartoCSS)
  3. Adding Data (Shapefiles and OSM Database) (Editing OSM Data with JOSM Plugin)
  4. Styling with CartoCSS (Line Styling, Polygon Styling, Point Styling, Zoom Levels, Color Variables, Comments)
  5. Creating a Legend
  6. Exporting a Map (PNG Image & MBTiles)

demo map

Installing TileMill

Here we’ll demonstrate how to install TileMill on Windows. You can download installers for other operating systems at

tilemill setup

  • Run the installer to set up TileMill on your computer. The default options in the installation wizard should be fine.

  • Once TileMill is installed go to your Start Menu and click “Start TileMill.”

start tilemill

  • This will load the projects tab of the application. TileMill comes with several example projects that you can use to get started.

sample projects

Exploring TileMill

Let’s take a look at one of the sample projects to get an idea of TileMill’s features and what we can do. Open the sample project named “Geography Class.” It may take 10-20 seconds for the map to load.

tilemill interface

Notice the key elements of TileMill:


The map window shows what your map looks like according to your current styling. It will update as you change the data and styling of your project. You must click the “save” button for any changes to take effect. Sometime it takes a while to render all of the OSM data and so you may see a blank grid screen for a few minutes.


You can create a legend to sit on your map using HTML. To see and edit the HTML used to create the legend, click on the button in the bottom-left that looks like a hand. Use previous projects, like Openstreetmap DC, to get ideas for how you would like your legend to look.

hand button


The teaser, which defines the pop-ups or information that show when you scroll or click on featured parts of the map, is created with HTML just like the legend. On this map the teaser changes flags depending on the country that the user hovers the mouse over.


This is the most important part of TileMill in terms of styling the map. Any TileMill project will have a number files like this which describe the way the map data should be styled. The language used is called CartoCSS, because it is similar to CSS but specifically designed for styling maps. We will look more closely at CartoCSS later in this chapter, but for now look at the three files that are used to the style the “Geography Class” map. The first file, style.mss contains code that does basic styling for the map, defining the color of bodies of water and the outline of the continents. labels.mss describes how the country names should be displayed. It includes information on the font, the size of the text, and more. It also indicates that when the user is zoomed out quite far, the map should display country abbreviations instead of their full names. Lastly, rainbow.mss describes how each country should be colored. In this file, nearly every country is manually given a color for the map.

Feel free to play around with this sample project to see how different features work. Anytime you change the CartoCSS files you can reload the map by clicking “Save.” When the map reloads it will incorporate your changes into the styling. TileMill is quite intelligent, and if you make a mistake in the CSS it will alert you that there is an error when you try to save it.

If you would like to change the project settings, click on the wrench in the upper right corner. The Geography Class project will only let you zoom in about halfway on the map. If you enter the settings you can adjust the zoom level to go deeper. Try moving it from 0 to 8 to 0 to

  1. This will allow you to zoom in further on the map.

zoom control

Adding Data

The project already has a number of layers, that you can view by clicking the “Layers” button in the bottom left corner.

tilemill layers

This list shows all of the layers in your project. The icon to left of each layer name indicates whether it is a point, line, or polygon layer. To the right of each layer name are buttons which let you view the layer data or edit settings.

Add a New Shapefile Layer

  • Let’s add a new shapefile layer to the map. Click “Add Layer.”

tilemill add layer

  • The ID is the name you want to give for your layer. It can be anything you want, but can only contain letters, numbers, dashes, and underscores, and it can’t have the same name as another layer in your project.

    You can apply any number of classes to your layer. A class helps you identify layers when doing CSS styling. For example, if you have many layers that all contain water polygons, you can give each layer the class “water.” Then you can use this class name to easily style them all at the same time in your CSS.

    The Datasource is the file you are loading in as a layer. This can be a CSV, shapefile, GeoJSON, KML, or GeoTIFF. In this example, we are using a shapefile containing polygons of the regions in the country of Georgia. This field must be supplied when creating a new layer.

    The SRS is the Spatial Reference System of your data. In most cases TileMill can automatically detect the correct SRS.

  • When you are finished with these options, click “Save” to add the new layer to the project. If you are following along, click “Save & Style.” This will automatically create a basic style for the new layer.

  • On the layers tab find your new layer and click the “Zoom to extent” button.

zoom to extent

  • This will zoom to the new layer. If you selected “Save & Style” it will come with some basic styling.

georgia basic styling

  • Notice that the new layer is displayed above all the other layers. If you wanted it, for example, to be displayed beneath the labels, you can grab the icon next to it on the layers tab, and drag it below the country-name layer. Remember that you must save the project before the map will be updated.

Add Your OSM Database

Now let’s see how we can add the PostGIS database that we filled with OpenStreetMap data in Chapter 1 of this Manual.

  • Go to the Layers tab and click “Add Layer.”
  • Click on the “PostGIS” button.

    This is similar to the way we added a shapefile layer above. The main difference is that we need to supply the connection parameters to our PostGIS database.

db connection parameters

  • Next to “Connection”, enter the following:

    host=localhost dbname=osm user=postgres password=my_password

    Replace my_password with your actual password.

  • Next to “Table or subquery”, enter: planet_osm_roads

    Note that you could also enter planet_osm_point, planet_osm_line, or planet_osm_polygon.

  • Lastly, you will need to change the SRS to WGS84.

  • Click on “Save & Style,” and your new layer should be added to the project, along with some basic styling. Zoom to the layer extent to see how it looks.

layer extent

JOSM Plugin

TileMill has a JOSM plugin which can be used to launch JOSM and load OpenStreetMap data for the area that you are currently viewing. This can be useful if you are using OSM data and you notice mistakes that you want to correct while you are styling your maps. You may skip this section if you don’t think you will need it, but here we will demonstrate how to activate this plugin:

  • Go to the Plugins tab and Install JOSM Editor.

josm plugin

  • Open JOSM. Note that you must have the Remote Control feature enabled in the JOSM preferences.

  • In TileMill, navigate to the area that you want to edit. Click ¨Edit in JOSM¨.

edit in josm

  • JOSM will begin to download the OpenStreetMap data for the area that you are viewing in TileMill. You can make your edits to the OSM data and upload your changes to the server.

Note that the edits you make will not show up in TileMill, because you have edited the main OSM database. You would need to update the data you are using in TileMill in order to incorporate the latest changes to OpenStreetMap.

Styling with CartoCSS

Now it’s time for the fun part, styling our map! As mentioned previously, TileMill uses a language called CartoCSS to style the map data. If you are at all familiar with CSS, CartoCSS will be familiar to you. If you’re not familiar with CSS, it will be quite understandable anyway.

With TileMill you are allowed to style different types of layers in different ways. For Line Layers you can style the line and labels, create a pattern to go inside the line, add markers, and add a shield, as when you want to put a number on a road. For Polygon Layers you can style the polygon and labels, create a pattern inside the polygon or inside the outlining line and add markers. For Points Layers you can style the points and labels, and add shields or markers.

Note that there are different files in the Geography Class project. Creating multiple files is simply a matter of convenience, because they are all compiled into the same stylesheet in the end anyway. But it’s a good idea to keep certain styling information together - for example, all the labels in one file, and so forth.

Line Styling

Let’s start out with line styling. When we added the planet_osm_roads layer from our PostGIS database, TileMill automatically created some basic styling at the bottom of the style.mss file.

#planetosmroads {

This code is fairly simple. #planetosmroads is what is known as a selector. In this case, we are saying, “select everything with the ID planetosmroads and apply the following styles.” After we have used this selector to define what we want to style, we apply some basic styles. line-width:1; indicates that the lines should be one pixel thick. line-color:\#168; indicates that the lines should be a bluish color. Colors are defined using hex, and may be in the format #xxx or #xxxxxx.

Note that if you define the same style for a layer more than once, the last style you define will be used. So:

#planetosmroads {

#planetosmroads {

would cause the layer to be colored with #861. The first declaration will be ignored.

There are many declarations that you can make for lines. Here is an example:

#planetosmroads {
 // sets the line width to 0.5 pixels
 line-width: 0.5;
 // sets the line color to #1a6e8a
 line-color: #1a6e8a;
 // makes the line 80% opaque (20% transparent)
 line-opacity: 0.8;
 // lines will be rounded at the end
 line-join: round;
 // lines will be a series of dashes; in this
 // case, the dashes will go 6px line, 2px empty,
 // 2px line, 2px empty, and then repeat
 line-dasharray: 6,2,2,2;

Polygon Styling

Styling polygons is quite similar to styling lines. Note that you can use all of the same attributes that you used for lines, in addition to new attributes. This is because when a polygon is drawn, it has characteristics both for the style inside the polygon, and for the outline drawn around it. Thus, any line attributes provided for a polygon will be applied to its outline. Let’s look at an example:

#georgia_regions {
 line-dasharray: 6,6;

This causes the layer to look like this: georgia 1

Note that the line attributes affect the polygon outline. We use polygon-fill to affect the color inside the polygons, and polygon-opacity to change their transparency.

Point Styling

For points layers, you will often want to use your own icons to represent points. This can easily be done by supplying the path of your icon in the CartoCSS file. For example:

#cities {
 point-file: url(icons/star-10.png);

You can get a complete list of style attributes by clicking on the parentheses button in the lower left of TileMill.


A Word About Tiles

Let’s take a moment to understand the way that slippy maps work, to better grasp what we mean by zoom levels. You may have noticed in the upper left corner of the map are buttons that allow you to zoom in and out, and also the word “Zoom” with a number next to it.

zoom buttons

This indicates the current zoom level of the map. This can range from 0 up to 22, depending on your project settings. The higher the zoom level, the further you are zoomed into the map. If you go out to zoom level 0, you’ll see the whole world.

As we mentioned in the introduction, slippy maps work because they create a whole lots of little image tiles at different zoom levels. Each tile is an image 256 pixels by 256 pixels. At zoom level 0, TileMill only generates one tile, and the whole world is contained on it. At zoom level 1, that one tile is divided into four tiles. At zoom level 2, each of the four tiles is divided into four more, resulting in 16 tiles. This pattern continues for as menu zoom levels as you want.

Zoom Level 0 - One Tile one tile

Zoom Level 1 - Four Tiles four tiles

Zoom levels are important to understand when styling, because as we’ll see in the next section, sometimes you want different styles to show at different zoom levels.

Complex Selectors

We discussed selectors a little bit previously, but now let’s learn how to use them to get more out of our maps. We already saw how we can use layer IDs to select specific layers and apply style declarations:

#cities {
 point-file: url(icons/star-10.png);

What if we want to select only some of the features in that layer, based on the data? We can change our selector and pass in an argument using our data table. The following will display stars icons for only the cities in Uruguay:

#cities[SOV0NAME='Uruguay'] {
 point-file: url(icons/star-10.png);

The same can be done for any column in the attribute table of a layer. The labels.mss file already uses this type of selector for the cities styling:

#cities[ADM0CAP=1][zoom\>3] {

This selector adds another element, the zoom level. Using this type of selector, we can easily tell TileMill at what zoom levels we want the styling to be displayed at. In the above example, any styling that is inside the brackets will only be displayed when the user is zoomed in past zoom level 3. This is why city names are not shown on the map when you are zoomed all the way out.

Zoom Level 5 zoom five

Zoom Level 3 zoom three

You will notice another type of selector in the rainbow.mss style that looks like this:

#country::land-glow-outer[zoom>1] {

The layer that these declarations are affecting is #country, and it is set to function only above zoom level 1. But why does it have the ::land-glow-outer?

First, remember that the following code will cause the first statements to be ignored:

#country {
 line-color: #000;
 line-width: 6;
#country {
 line-color: #999;
 line-width: 3;

This will cause the appropriate lines to be 3 pixels wide and colored #999. But sometimes you want to render the same layer multiple times. For example if you want to draw a line that has an outline or a glow, you will want TileMill to first draw a thick line, and then draw a thinner line on top of it. To do this, you select the layers with attachments. This is a way for you to render a layer using multiple styles.

#country::outline {
 line-color: #000;
 line-width: 6;

#country::fill {
 line-color: #999;
 line-width: 3;

In this example, we use the attachments ::outline and ::fill to create copies of the same layer, and render it twice. Hence, TileMill will first draw the layer with the color #000 and width of 6 pixels, and then draw it again with a color #999 and width of 3 pixels. In the rainbow.mss file, this characteristic is used to create and outer and inner glow for each country.

For more information on selectors click on the “Intro” tab of the Help.

Color Variables

Variables are a convenience offered by CSS that allow us to keep our color scheme all in one place. When writing lengthy CartoCSS, you will often find that you reuse the same colors again and again for different layers and different features. If you want to adjust those colors later on, you have to go through and change every single value. Instead, you can use variables to represent specific colors, and then use these variables in the CartoCSS.

You’ll see this at the top of the rainbow.mss file:

@white: #F0F8FF; /* blue-tinted, for Antarctica */
@red: #fdaf6b;
@orange: #fdc663;
@yellow: #fae364;
@green: #d3e46f;
@turquoise: #aadb78;
@blue: #a3cec5;
@purple: #ceb5cf;
@pink: #f3c1d3;
@f00: #f00;

These are variable definitions. Any time you use the variables defined here (such as @green or @pink) they will be replaced by the color values that are defined.


You can add comments into your CartoCSS files. Any text placed between /* and */ will be ignored by TileMill. Also, anytime you use two forward slashes, the remainder of the line will be considered a comment. Example:

/* This is
a comment \*
// this is a comment too!

Creating a Legend

  • It is easy to create a legend using HTML with TileMill. Simply click on the hand symbol in the lower right-corner to open the Legend Window.

hand button

  • On the “Legend” tab you’ll see the HTML code that makes up the legend bar in the lower right corner of the map. If you are comfortable writing HTML code, you can easily make this legend your own.

sample legend

Exporting Your Map

After you’ve designed a beautiful map using TileMill, you’re definitely going to want to export it for the world to see. TileMill comes with several options for exporting, as you can see when you click on the “Export” button.

Export a PNG Image File

export button

  • To export a PNG image file, click on “PNG.”
  • Choose the area you want to export by holding SHIFT on your keyboard and drawing an area on the map. You can zoom in if you need to.

shift and drag

  • In the panel on the right, you can change the name of the image file, and the dimensions in pixels of the image.

png dimensions

  • When you are finished click “Export.”
  • The image rendering will process and when it’s finished you can save the image by clicking on “Save.”

save png

Export MBTiles

MBTiles is a format for storing image tiles - all the little 256x256 images that make up the slippy map.

  • To export tiles, click “MBTiles” on the Export menu.

  • Once again you can select the area that you would like to export by holding SHIFT and dragging a box on the map.

  • You will also want to adjust the zoom setting so that your file does not grow too big. Remember that every zoom level has four times as many tiles as the previous zoom level, so that number of image tiles grows exponentially. It will be best if you can keep your MBTiles file under 50MB for now.

zoom control

If you have a MapBox account (what we created in the previous chapter), you can upload MBTiles files as map layers to be displayed on the web.


In this chapter we learned how to use TileMill, a powerful application for applying custom cartography to our maps. If you want to learn more, MapBox has developed extensive documentation on using TileMill, which you can explore here.

 Return to top of page

Official HOT OSM learning materials