---
title: "Deploy PostGIS | (Just Updated) Spatial Database With Routing, H3 and pgvector"
description: "Spatial Postgres with pgRouting, H3 and pgvector, tuned to your plan size"
category: "Storage"
url: https://railway.com/deploy/postgis-or-just-updated-spatial-database
---

# Deploy PostGIS | (Just Updated) Spatial Database With Routing, H3 and pgvector

Spatial Postgres with pgRouting, H3 and pgvector, tuned to your plan size

**[Deploy PostGIS | (Just Updated) Spatial Database With Routing, H3 and pgvector on Railway](https://railway.com/template/postgis-or-just-updated-spatial-database)**

- **Creator:** SuperSlowSloth
- **Category:** Storage

## Template content

### postgis

- **Image:** ghcr.io/bon5co/postgis-railway:18-3.6

## Documentation

# Deploy and Host PostGIS on Railway

PostGIS turns PostgreSQL into a spatial database: geometry and geography columns, GiST
indexes, `ST_Intersects` / `ST_DWithin` / `ST_Distance`, raster, topology, and the tiger
geocoder. This template runs **PostgreSQL 18.4 with PostGIS 3.6.4**, and adds the three
extensions a real spatial project reaches for next — **pgRouting 4.0.1** for shortest
path and driving distance, **H3 4.2.3** for hexagonal indexing, and **pgvector 0.8.6**
for embeddings — already installed and already enabled in your database.

## About Hosting PostGIS

The database is exposed over a Railway **TCP proxy**, so any client — psql, QGIS, GDAL,
Prisma, PostgREST, a GIS worker in another project — connects with an ordinary
`postgresql://` URL. The `DATABASE_URL` and `DATABASE_PRIVATE_URL` variables are filled
in for you, the password is generated per deploy, and everything durable lives on a
volume mounted at `/var/lib/postgresql`, the parent of the data directory, so a redeploy
keeps your data.

Three things are handled that a stock `postgis/postgis` container does not handle on
Railway:

- **The server is sized from the container's own cgroup limits at boot.** PostgreSQL
  ships 128 MB `shared_buffers`, 4 MB `work_mem`, 64 MB `maintenance_work_mem` and a
  4 GB `effective_cache_size` that describes no container in particular. Those are the
  settings a spatial workload feels first: GiST index builds are
  `maintenance_work_mem`-bound and spatial joins spill to disk on 4 MB. On an 8 GB
  instance this deploy comes up with 1907 MB `shared_buffers` and 119 MB `work_mem`
  instead; measured on the same 5-million-point `ST_Intersects` join in a 2 GB / 2 vCPU
  container, 2.20 s becomes 1.23 s. Every value is passed as a start-up argument, so
  your own `ALTER SYSTEM` still overrides it.
- **TLS uses a key pair generated for your deploy, on your volume.** The usual shortcut
  is to point `ssl_key_file` at Debian's `ssl-cert-snakeoil` files, which are created
  when the image is built — so every container started from that public image shares one
  private key that anybody can pull and read. This deploy generates its own on first
  boot and keeps it across redeploys.
- **The listener is pinned to 5432.** Railway injects `PORT` into every service and
  PostgreSQL reads it, which would move the server off the port the TCP proxy dials.

## Why Deploy PostGIS?

Managed spatial databases are priced as a premium tier, and the free tiers cap rows or
area. Self-hosting on Railway gives you the full extension set with no row limits, usage
billing instead of a fixed plan, and private networking to the rest of your project, so
your API talks to the database over the internal network at no egress cost.

Running it here rather than on a VPS also means no `apt-get install postgresql-18-postgis`,
no `initdb` tuning pass, no certificate to renew, and no server to patch.

## Common Use Cases

- **Store locator / nearest-neighbour search** — `ST_DWithin` with a GiST index over
  points of interest, with the trigram and fuzzy-string extensions already present for
  the name search beside it.
- **Delivery and field-service routing** — pgRouting over an OpenStreetMap extract for
  shortest path, driving distance and the travelling-salesperson solver.
- **Geospatial analytics and dashboards** — H3 hex aggregation over event data, raster
  overlays, and `pg_stat_statements` for finding the query that costs the most.
- **RAG over places** — pgvector embeddings and geometry in the same row, so a single
  query can filter by similarity and by distance.
- **A GIS backend for QGIS, GeoServer, PostGREST or Prisma** — connect over the public
  TCP proxy with `sslmode=require`.

## Dependencies for PostGIS

- The image [ghcr.io/bon5co/postgis-railway](https://github.com/bon5co/postgis-railway),
  built from `postgis/postgis:18-3.6` (PostgreSQL 18.4, PostGIS 3.6.4, GEOS 3.13.1,
  PROJ 9.6.0, GDAL 3.10.3) with pgRouting, H3 and pgvector added.
- A Railway volume for the data directory and the TLS material.

### Deployment Dependencies

- No external service is required. The database runs alone.
- `POSTGRES_PASSWORD` is generated for you; `DATABASE_URL` and `DATABASE_PRIVATE_URL`
  are derived from it, so nothing has to be filled in on the deploy form.
- Source: [PostGIS](https://postgis.net) · [pgRouting](https://pgrouting.org) ·
  [H3](https://github.com/zachasme/h3-pg) · [pgvector](https://github.com/pgvector/pgvector)

### Extensions enabled on first boot

`postgis`, `postgis_topology`, `postgis_raster`, `postgis_tiger_geocoder`,
`fuzzystrmatch`, `pgrouting`, `h3`, `h3_postgis`, `vector`, `hstore`, `pg_trgm`,
`btree_gist`, `uuid-ossp`, `pg_stat_statements` — in your database and in
`template_postgis`, so every database you create from that template starts spatial.


## Similar templates

- [Garage S3 Storage](https://railway.com/deploy/garage-s3-storage) — Ultra-light S3 server: fast, open-source, plug-and-play.
- [Redis](https://railway.com/deploy/redis-1) — Self Host Latest Redis with Railway
- [EasyImg](https://railway.com/deploy/easyimg) — Simple self-hostable Nuxt.js personal image hosting system.

Open this page in a browser: https://railway.com/deploy/postgis-or-just-updated-spatial-database
