An interactive map of the Swiss tech ecosystem β visualise which companies use which technologies, explore the developer landscape by city, and filter by commute time.
SwissDevMap is a full-stack web application that plots Swiss tech companies on an interactive map and lets you explore the local developer ecosystem at a glance. Each company is tagged with the technologies it uses (React, Go, Kubernetes, AWS, β¦), and you can filter, search, and overlay a heatmap to answer questions like:
- "Which companies in ZΓΌrich use Rust?"
- "How many firms within 30 minutes by public transport are hiring Python developers?"
- "Where is Go most popular in Switzerland?"
| Feature | Description |
|---|---|
| πΊοΈ Interactive map | Company markers colour-coded by dominant tech category (frontend / backend / cloud / devops) |
| π₯ Heatmap overlay | Visualise the geographic density of any technology or cloud provider |
| π Commute filter | Enter any Swiss address and filter companies reachable within a chosen travel time |
| π·οΈ Tech-stack filters | One-click chips for every major tag across Frontend, Backend, Cloud, and DevOps |
| π’ Company-type filter | Filter by Enterprise, Fintech, Consulting, E-Commerce, Industrial, etc. |
| β Add a company | Submit missing companies via the in-app form |
| π Dark / light mode | Toggle between themes |
| π± Responsive | Full-screen map on desktop; collapsible bottom sheet on mobile |
| Tool | Purpose |
|---|---|
| React 18 + TypeScript | UI framework |
| Vite 5 | Build tool & dev server |
| Leaflet + react-leaflet | Interactive map rendering |
| leaflet.heat | Heatmap layer |
| Zustand | Global state management |
| Axios | HTTP client |
| Tool | Purpose |
|---|---|
| Express + TypeScript | REST API |
node-postgres (pg) |
PostgreSQL client |
| Playwright | Headless scraping |
| Cheerio | HTML parsing |
| node-cron | Scheduled scraper jobs |
| Tool | Purpose |
|---|---|
| PostgreSQL 16 | Primary database |
| Docker / Docker Compose | Local database setup |
| npm workspaces | Monorepo tooling |
swissdevmap/
βββ backend/
β βββ src/
β βββ db/
β β βββ schema.sql # Table definitions (companies, tech_tags, job_postings)
β β βββ seed.ts # Seed script β loads companies into Postgres
β β βββ seed-data.example.ts # Example company data format (copy β seed-data.ts)
β βββ routes/
β β βββ companies.ts # GET /api/companies (filter by tag / type)
β β βββ heatmap.ts # GET /api/heatmap (GeoJSON points for a tech)
β β βββ commute.ts # POST /api/commute (travel-time filtering)
β βββ scrapers/
β β βββ jobsch.ts # Scraper for jobs.ch
β βββ index.ts # Express app entry point
βββ frontend/
β βββ src/
β βββ components/
β β βββ Map.tsx # Leaflet map, markers, heatmap layer
β β βββ Sidebar.tsx # Filter panel (overlay on desktop, sheet on mobile)
β β βββ CommuteFilter.tsx # Commute distance / time input
β β βββ CompanyForm.tsx # "Add missing company" form
β βββ store/
β β βββ mapStore.ts # Zustand store (companies, filters, state)
β βββ App.tsx
β βββ index.css # Global styles & design tokens
βββ docker-compose.yml # Spins up a local Postgres instance
βββ .env.example # Environment variable template
βββ package.json # Root workspace (runs both apps concurrently)
- Node.js β₯ 18
- Docker (for the local Postgres database)
- A free Mapbox token β get one at account.mapbox.com (used for geocoding in the commute filter)
git clone https://github.com/your-username/swissdevmap.git
cd swissdevmap
npm installcp .env.example .envThen open .env and fill in the required values:
# PostgreSQL connection string
DATABASE_URL=postgresql://swissdevmap:swissdevmap_secret@localhost:5432/swissdevmap
# Node environment
NODE_ENV=development
# Backend port
PORT=3001
# Mapbox token (for commute geocoding)
VITE_MAPBOX_TOKEN=pk.your_token_here
# Backend URL consumed by the frontend
VITE_API_URL=http://localhost:3001docker compose up -dThis starts a Postgres 16 container, creates the swissdevmap database, and applies the schema automatically via the schema.sql init script.
Copy the example seed file and add your companies:
cp backend/src/db/seed-data.example.ts backend/src/db/seed-data.ts
# Edit seed-data.ts with real company dataThen run the seed script:
npm run seed --workspace=backendNote:
seed-data.tsis.gitignored so your company list stays private.
npm run devThis runs both the backend (:3001) and frontend (:5173) concurrently.
Open http://localhost:5173 in your browser.
Returns an array of companies matching the given filters.
| Query param | Type | Description |
|---|---|---|
tag |
string (repeatable) |
Filter by one or more tech tags, e.g. ?tag=React&tag=Go |
type |
string (repeatable) |
Filter by company type, e.g. ?type=Fintech |
Returns a GeoJSON FeatureCollection of points, each with an intensity property, for rendering the heatmap layer.
Accepts a start address and travel parameters, returns an array of company IDs reachable within the specified time.
Triggers the Jobs.ch scraper.
Returns { status: 'ok', service: 'SwissDevMap API', timestamp }.
-- Core tables (defined in backend/src/db/schema.sql)
companies (
id UUID PRIMARY KEY,
name TEXT,
uid TEXT, -- Swiss company registration number (optional)
website TEXT,
city TEXT,
lat DOUBLE PRECISION,
lng DOUBLE PRECISION,
type TEXT -- e.g. 'Enterprise', 'Fintech', 'Consulting'
)
tech_tags (
id UUID PRIMARY KEY,
company_id UUID REFERENCES companies(id),
tag TEXT, -- e.g. 'React', 'Go', 'Kubernetes'
category TEXT, -- 'frontend' | 'backend' | 'cloud' | 'devops'
source TEXT -- 'seed' | 'scraper'
)
job_postings (
id UUID PRIMARY KEY,
company_id UUID REFERENCES companies(id),
title TEXT,
url TEXT,
posted_at TIMESTAMP
)Contributions are welcome! The most impactful way to improve the map is to add more companies to the seed data or improve the scrapers to pull richer tech-stack information.
- Fork the repository
- Create a feature branch:
git checkout -b feat/my-feature - Commit your changes and open a pull request
MIT
