One Domain, Two Hosts

How we launched two apps on the same domain with Netlify

Portal by New Visions

A few months ago at New Visions we were in the midst of a big rebranding project. As part of this endeavor we wanted a new landing page to show off our new product branding. This landing page had to be fast to load and easy to update — these requirements led us to choose Next.js. A third requirement though didn’t have quite as obvious an answer.

You see, we had an existing domain for the app, but to keep existing traffic we wanted use this same domain name for our landing page. And we couldn’t just steal this domain for the static site, since existing in-app links needed to work. We needed some way to host both a static site and full single-page app on the same domain.

At first I considered abandoning the static site idea altogether and building a landing page within the app, but having to load an entire SPA just for some marketing content was silly — and the Lighthouse scores proved as much.

My first attempt at a double host was to point our domain to the static site on Firebase, and use Cloud functions to manually proxy the relevant app traffic to the app’s host. This approach resulted in some severe latency in the app, which was not at all acceptable.

I also attempted the inverse, where traffic to the static page was proxied. This just flipped which page experienced latency, and destroyed any gains we had from using a static site.

Finally, I realized that Netlify supports this behavior out of the box. After hosting the static site on Netlify, I updated my netlify.toml config, which enabled me to direct any requests to a url that didn’t exist as a static page straight to the app.

[[redirects]]
from = “/*”
to = “https://my-spa.example.com/:splat"
status = 200

Let’s break this down. This config rule tells Netlify to take any request (/*) and send it to https://my-spa.example.com. These rules won’t apply unless the url doesn’t exist on the Netlify-hosted site already. So a static/privacy-policy page would would be shown as opposed to redirecting that path.

Next, the :splat essentially means “copy everything in the path and paste it here”. For instance, a request to my-static-site.netlify.app/login would be sent to my-spa.example.com/login. Finally the 200 status code makes this redirect virtually indistinguishable to the browser.

Conceptually this is the same as the first proxy approach, but without the latency. To the user, this setup seems like both the static site and SPA are one seamless experience hosted on the same domain.

Check out the landing page now live at portal.newvisions.org!

I’m a UI Engineer based in New York, working on the Portal by New Visions. I’m online, and will occasionally tweet things.

🗽🇨🇦 | UI Engineer at New Visions for Public Schools | Engineering grad from uWaterloo

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store