A modern, interactive postal code directory for Somalia — browse every region, search cities, view postal codes on an interactive map, and copy formatted addresses in one click.
The Somali Postal Code Explorer is a full-stack web application built with Next.js App Router that provides a clean, searchable, and interactive directory of postal codes across all 18 regions of Somalia. It de-duplicates raw postal records so each city appears exactly once, with all its codes grouped together for a better user experience.
| Feature | Description |
|---|---|
| 🗺️ Interactive Map | Leaflet-powered map showing city markers; click to select a city |
| 🔍 Live Search | Filter by city name, region name, region code, or postal code |
| 📋 One-click Copy | Copy individual codes, all codes, or a full formatted address |
| 🏷️ Region Filter | Quick-filter pills for all 18 Somali regions |
| 📊 Stats Dashboard | Live counts of cities shown, regions, and unique postal codes |
| 📱 Responsive | Fully optimised for mobile, tablet, and desktop |
somali-postel-code/
├── app/
│ ├── layout.tsx # Root layout with metadata, fonts & analytics
│ ├── page.tsx # Entry point — loads postal data & renders MapApp
│ └── globals.css # Global Tailwind CSS base styles
│
├── components/
│ ├── map-app.tsx # 🧠 Main application component (search, filter, UX)
│ ├── somalia-map-fullscreen.tsx # Leaflet map with city markers
│ ├── map-leaflet.tsx # Low-level Leaflet wrapper
│ ├── postal-code-content.tsx # Postal code display card
│ ├── postal-code-map.tsx # Embedded map tile
│ ├── postal-code-table.tsx # Tabular view of codes
│ ├── search-bar.tsx # Reusable search bar
│ ├── somali-flag.tsx # SVG Somali flag asset
│ ├── theme-provider.tsx # next-themes provider wrapper
│ └── ui/ # shadcn/ui component library (57 components)
│
├── data/
│ └── postal-codes.ts # 📦 Source dataset — typed PostalCode[] array
│
├── lib/
│ ├── postal-map.ts # City grouping, filtering & region summary logic
│ ├── somalia-postal.ts # Region codes, address formatting utilities
│ └── utils.ts # Shared utility helpers (cn, etc.)
│
├── hooks/
│ └── use-mobile.ts # Responsive breakpoint hook
│
├── styles/ # Additional CSS modules (if any)
├── next.config.mjs # Next.js configuration
├── tailwind.config.ts # Tailwind CSS v4 configuration
├── tsconfig.json # TypeScript configuration
└── package.json
| Tool | Version |
|---|---|
| Node.js | ≥ 18.x |
| pnpm | ≥ 9.x (recommended) |
You can also use
npmoryarn— just replacepnpmcommands accordingly.
# 1. Clone the repository
git clone https://github.com/your-username/somali-postel-code.git
cd somali-postel-code
# 2. Install dependencies
pnpm install
# 3. Start the development server
pnpm devOpen http://localhost:3000 — the app hot-reloads on every file save.
| Command | Description |
|---|---|
pnpm dev |
Start Next.js development server with hot reload |
pnpm build |
Create an optimised production build |
pnpm start |
Run the built production server locally |
pnpm lint |
Run ESLint across the codebase |
data/postal-codes.ts ← Static typed PostalCode[] dataset
│
▼
app/page.tsx ← Server Component: passes data as props
│
▼
components/map-app.tsx ← Client Component: state, search, filter logic
├── lib/postal-map.ts buildCityGroups() — dedup + group by city
│ filterCityGroups() — live search
│ buildRegionSummaries() — region stats
│
├── lib/somalia-postal.ts getSomaliaRegionCode() — normalise region names
│ formatSomaliaPostalCode() — format codes
│ buildSomaliaAddressLines() — full address format
│
├── SomaliaMapFullScreen ← Leaflet map (dynamically imported, no SSR)
└── City Directory sidebar ← Scrollable list with copy actions
// Raw source record (data/postal-codes.ts)
interface PostalCode {
city: string
postalCode: string
region: string
latitude: number
longitude: number
}
// Deduplicated city group (lib/postal-map.ts)
interface CityGroup {
id: string // "cityname|regionCode" composite key
city: string
region: string
regionCode: string // 2-letter ISO-style code e.g. "BN", "WG"
latitude: number // averaged from all raw records
longitude: number
postalCodes: string[] // sorted, deduplicated
totalEntries: number
}All 18 official Somali regions are supported with their 2-letter codes:
| Code | Region | Code | Region |
|---|---|---|---|
AD |
Awdal | MD |
Mudug |
BK |
Bakool | NG |
Nugaal |
BN |
Banaadir | SG |
Sanaag |
BR |
Bari | SD |
Shabeellada Dhexe |
BY |
Bay | SH |
Shabeellada Hoose |
GG |
Galgaduud | SL |
Sool |
GD |
Gedo | TG |
Togdheer |
HR |
Hiiraan | WG |
Waqooyi Galbeed |
JD |
Jubbada Dhexe | JH |
Jubbada Hoose |
| Package | Version | Purpose |
|---|---|---|
next |
16.1.6 | App framework (App Router) |
react / react-dom |
19.2 | UI library |
typescript |
5.7.3 | Type safety |
| Package | Purpose |
|---|---|
tailwindcss v4 |
Utility-first CSS |
@radix-ui/* |
Accessible headless component primitives |
lucide-react |
Icon library |
class-variance-authority + clsx + tailwind-merge |
Dynamic class utilities |
next-themes |
Dark/light theme toggling |
tw-animate-css |
Animation utilities |
| Package | Purpose |
|---|---|
leaflet + @types/leaflet |
Interactive map tiles and markers |
| Package | Purpose |
|---|---|
react-hook-form + @hookform/resolvers |
Form state management |
zod |
Schema validation |
| Package | Purpose |
|---|---|
date-fns |
Date formatting |
recharts |
Chart components |
embla-carousel-react |
Carousel component |
@vercel/analytics |
Page analytics |
All postal data lives in a single TypeScript file:
// data/postal-codes.ts
export const SOMALI_POSTAL_CODES: PostalCode[] = [
{
city: 'Mogadishu',
postalCode: '1001',
region: 'Banaadir', // ← Use the region's English or Somali name
latitude: 2.0469,
longitude: 45.3182,
},
// ...
]Rules:
postalCodeshould be a numeric string (e.g."1001").regionis normalised automatically — accepted aliases are defined inlib/somalia-postal.ts.- Duplicate
city + regionrows are automatically merged. You can safely add multiple rows for the same city with different postal codes. - After editing, run
pnpm devto see changes immediately — no rebuild required.
The Leaflet map is loaded dynamically with SSR disabled to avoid window is not defined errors during server rendering:
// components/map-app.tsx
const SomaliaMapFullScreen = dynamic(
() => import('@/components/somalia-map-fullscreen'),
{ ssr: false, loading: () => <div className="h-full w-full animate-pulse bg-slate-100" /> }
)Map tiles are provided by OpenStreetMap. No API key is needed.
- Push your code to GitHub.
- Import the repository in Vercel Dashboard.
- Vercel auto-detects Next.js — no configuration needed.
- Click Deploy.
Vercel Analytics is already wired up via
@vercel/analytics. It will activate automatically once deployed on Vercel.
# Build the production bundle
pnpm build
# Start the production server
pnpm startThe app listens on port 3000 by default. Use a reverse proxy (Nginx, Caddy) to serve it publicly.
FROM node:20-alpine AS base
WORKDIR /app
COPY . .
RUN npm install -g pnpm && pnpm install --frozen-lockfile
RUN pnpm build
EXPOSE 3000
CMD ["pnpm", "start"]docker build -t somali-postal .
docker run -p 3000:3000 somali-postalConfigured in tsconfig.json — use @/ to import from the project root:
import { SOMALI_POSTAL_CODES } from '@/data/postal-codes'
import { buildCityGroups } from '@/lib/postal-map'This project uses shadcn/ui components located in components/ui/. To add a new component:
npx shadcn@latest add <component-name>next.config.mjs has ignoreBuildErrors: true for faster iteration. For production, it is recommended to re-enable strict type checking:
// next.config.mjs
typescript: {
ignoreBuildErrors: false, // ← re-enable for a production release
}This project has no required environment variables — it is fully static with no database or external API calls.
If you add external services in the future, create a .env.local file (never commit it):
# Example future variables
NEXT_PUBLIC_MAP_TILE_URL=https://...
SOME_API_SECRET=...- Fork this repository.
- Create a feature branch:
git checkout -b feat/add-more-cities - Commit your changes:
git commit -m "feat: add postal codes for Hiiraan region" - Push and open a Pull Request.
- Add missing cities for under-represented regions
- Add Somali language (
so) translations for region names - Export to CSV / JSON download feature
- Add address validation utility
- Add unit tests for
lib/postal-map.tsandlib/somalia-postal.ts
This project is licensed under the MIT License — you are free to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the software, as long as the original copyright notice is included.
See LICENSE for the full text.
- Map data © OpenStreetMap contributors
- Icons by Lucide
- Map rendering by Leaflet
- UI components by shadcn/ui