title: | We migrated our blog to Val Town, and you should too |
---|---|
description: | This very blog is now hosted on Val Town |
pubDate: | 2025-04-04T00:00:00.000Z |
author: | Steve Krouse |
Today we migrated our blog to Val Town 🥳
We completed this migration in about one day of work. Now our deployments are instant (~100ms), and we've greatly simplified our blogging stack.
Before | Now | |
---|---|---|
Rendering | Astro | React |
Version control | Github | Val Town |
Text editing | local editor | Val Town |
Hosting | Cloudflare | Val Town |
CDN | Cloudflare | Cloudflare |
Maybe! It depends on your constraints and what matters to you. We care deeply about:
- Tight feedback loops
- Simple, browser-based workflows
We also care deeply about dogfooding, but unless you're us – and unfortunately most of you aren't – this doesn't apply to you.
We are obsessed with tight feedback loops.
"Creators need an immediate connection to what they're creating."
– Bret Victor, "Inventing on Principle"
In some ways, this singular comittment to tight feedback loops is what seperates Val Town from all other code hosting & deployment platforms. We believe that you should be able to iterate in your production environment directly, not write locally and then deploy later.
In Val Town, a save is a deploy, and it happens in about 100ms. We go to great technical lengths to make this possible. This means no waiting minutes to see what your post looks like live. And this goes for branches too. Every edit of every branch is also instantly deployed like a branch preview.
Simpler workflows is particularly important if you value casual contributors, such as less technical folks on your team or contributions from the broader community. If your blog is on Val Town, then you have a single place where the source code lives, is edited, collaborated on, and deployed. No need for anyone to install or use git, clone the repo locally, and install or use a local text editor. Contributors can remix your blog with a single click (after signing up for Val Town), make their edits, preview their deployed edits, and send you a pull request – all from the browser. (You can edit Val Town Projects locally with your preferred editor via our CLI if you prefer.)
The downsides:
- Val Town Projects are beta software, so you'd be on the cutting-edge alongside us.
- We're coming up with patterns that you'd get for free from Astro
- We haven't yet figured out a great story for image hosting and caching (right now we're just uploading to cloudflare out of band and linking; no images in source control yet; coming soon)
- Val Town doesn't yet have pull-request comments like Github does
- We don't have good workflows for bundlers or build steps, so it's harder to use anything that requires vite, etc.
Previously, our blog was:
- Built with Astro, a modern static site generator
- Deployed to Cloudflare Pages
- Updated through a GitHub workflow
While this setup worked well, we wanted:
- A browser-based editor
- Instant deploys (on feature branches and production)
- To dogfood
The new blog:
- Hosts new blog posts directly on Val Town as markdown files
- Proxies requests for old blog posts to the original Cloudflare Pages deployment
- Generates the full lists of posts (for the homepage) by splicing together the new posts and the old posts, which it gets via the old blog's RSS feed
We implemented the new blog system using:
- React for rendering components
- Tailwind CSS for styling
- Unified/Remark/Rehype for markdown processing
- RSS Parser for fetching posts from the old blog
Proxying is as easy as:
const OLD_BLOG_URL = "https://val-town-blog.pages.dev/";
const response = await fetch(
new Request(OLD_BLOG_URL + url.pathname + url.search, {
method: request.method,
headers: new Headers({ ...Object.fromEntries(request.headers) }),
}),
);
We fetch old posts via the https://val-town-blog.pages.dev/rss.xml
,
and combine them with the locally-hosted posts. We cache them both in-memory
on server startup.
// Example of how we fetch blog posts
async function getAllBlogPosts() {
// Get local posts from markdown files
const localPosts = await getLocalBlogPosts();
// Get posts from RSS feed
const rssPosts = await getRssBlogPosts();
// Merge and sort by date
return [...localPosts, ...rssPosts].sort((a, b) => {
return new Date(b.pubDate).getTime() - new Date(a.pubDate).getTime();
});
}
So far we've had reasonable success with this technique of migrating to Val Town quickly by proxying most old content, and only rebuilding the homepage. I first used this technique on my personal website, stevekrouse.com, and was pleased to see it continue to work here. If you, dear reader, have a blog you'd like to migrate to Val Town in this way and get stuck, shoot me an email at steve@val.town – I'd be happy to help.