There's a moment in every side project where you choose your tools, and that choice shapes everything that follows. When we rebuilt SurfTrip.ph from scratch in early 2026, we made a choice that raised a few eyebrows: we went with Perl.
Not legacy CGI Perl. Not the Perl of 2003. We went with Mojolicious — a modern, full-featured web framework that most developers under 30 have never heard of, and most developers over 40 stopped paying attention to about a decade ago. That's a shame, because it's genuinely excellent.
What SurfTrip.ph actually does
SurfTrip.ph is a Philippine surf guide — surf forecasts, spot guides, accommodations, and local knowledge for surfers exploring the islands. The data side is non-trivial: 7-day forecast data, tide predictions, hourly swell and wind readings, and astronomy data for multiple spots, all processed server-side and delivered fast on Philippine mobile connections where 3G is still a real scenario.
The old version was a CGI Perl app with Foundation 6 CSS and a MySQL database. It worked, but it was showing its age. The rebuild was an opportunity to do it properly.
Why Mojolicious
We weren't going to rewrite in Node or Python. The existing codebase was Perl, the author knows Perl well, and frankly — Perl is still one of the best languages for text processing, regex, and gluing systems together. The question was which Perl web framework to use.
Mojolicious won for a few reasons.
It's genuinely modern
Async I/O, WebSockets, a built-in test framework, a real template engine, a plugin system — all the things you'd expect from a 2020s framework. No CPAN dependency hell; the whole framework ships as a single distribution.
Mojolicious::Lite is perfect for this use case
The entire routing layer of SurfTrip.ph lives in one readable Perl file. Routes are declared cleanly, middleware hooks are straightforward, and the stash pattern for passing data to templates is intuitive.
get '/spots/:slug' => sub ($c) {
my $spot = get_spot_info($c->db, $c->param('slug'));
return $c->reply->not_found unless $spot;
$c->stash(spot => $spot);
$c->render(template => 'spot_info', layout => 'default');
};
Server-side rendering by default
No hydration. No client bundle. No build step. Mojo renders templates and sends HTML. Pages load fast because there's nothing to parse and execute before the user sees content. For a surf site where half your audience is on a phone with a weak signal, this matters more than any Lighthouse score.
Mojo::Pg is a joy
The PostgreSQL integration is clean, uses placeholders properly, and returns Mojo::Collection objects that chain naturally. Writing queries feels good.
return $db->query(<<'SQL', $spot_name)->hashes->to_array;
SELECT
PERCENTILE_CONT(0.5) WITHIN GROUP
(ORDER BY h.wave_height) AS wave_height_m,
PERCENTILE_CONT(0.5) WITHIN GROUP
(ORDER BY h.wind_speed) AS wind_speed
FROM tbl_hourly h
INNER JOIN tbl_spot_info i ON i.id = h.spot_id
WHERE LOWER(i.location_name) = LOWER(?)
AND h.forecast_date = CURRENT_DATE
SQL
The stack
| Layer | Choice | Why |
|---|---|---|
| Framework | Mojolicious Lite (Perl) | Fast, modern, zero dependency bloat |
| Database | PostgreSQL via Mojo::Pg | Solid, clean API, proper placeholders |
| Templates | Mojolicious .html.ep | Built-in, no extra deps, layout system |
| CSS | Vanilla CSS + custom properties | No preprocessor, no framework, no build step |
| JavaScript | Vanilla JS | No React, no Vue, no bundler, no node_modules |
| Maps | Leaflet.js + OpenStreetMap | No Google, no API key, self-hosted |
| Content | Markdown files | Git-trackable, CMS-ready, no schema changes |
| AI Forecasting | Alon AI by Code Mavericks | Philippine-specific surf forecast engine |
No npm. No webpack. No Docker. No microservices. One Perl process, one PostgreSQL database, flat files for content. Boring in the best possible way.
The cost argument nobody wants to make
We did consider a React frontend with a Next.js server layer, a Redis cache, and a proper cloud deployment. Then we remembered we were building a surf site, not a bank. The Perl process handles it fine.
This isn't a flex about being cheap. It's a deliberate engineering decision. Cloud bills that require a spreadsheet to understand are a tax on small projects. The renegade move in 2026 isn't building a microservices architecture — it's refusing to.
Content architecture we're proud of
One decision we're particularly happy with: long-form content lives in Markdown files, not the database.
Spot guides, article bodies, getting-there directions — all
.md files under a content/ directory.
The database owns structured data (forecast readings, accommodation
listings, spot coordinates). Markdown files own prose.
content/
spots/
baler/
overview.md
getting-there.md
la-union/
overview.md
getting-there.md
articles/
adfaa8c6-...uuid....md
about/
mission.md
system.md
alon-ai.md
A future CMS just needs to edit files. No schema changes, no migrations, no JSON crammed into a text column. Git-trackable, diff-readable, and it works at 11pm when you break something and need to roll back.
What surprised us about Mojolicious
The documentation is comprehensive but dry. It tells you everything the framework can do without always showing you why you'd want to. The best resource we found was reading the source code of other Mojo apps and the Mojolicious Growing guide — which walks through building a real app from a Lite script all the way to a full production setup. Start there, not the API reference.
The framework's real strength becomes obvious once you're inside it. The consistency of the API. The way hooks work. The fact that async and sync share the same interface. It's clearly been designed by someone who thought hard about developer experience, even if the marketing hasn't kept up.
If you're a Perl developer who hasn't looked at Mojolicious recently — look again. And if you're coming from another language and curious about what modern Perl looks like, mojolicious.org is the place to start. Not Stack Overflow threads from 2009. Not the Perl documentation from the Clinton administration. The Growing guide. You'll be surprised.
SurfTrip.ph is a Philippine surf guide. Check the forecast →
Questions or want to talk Perl and surf? Find us on Slack.