A few lessons from the trenches — some obvious in hindsight, some learned the hard way.
TL;DR
- Architect for SEO from day one, not as a post-launch patch
- Performance budgets aren't optional, they're a feature
- Decoupling frontend/backend early saves you months later
- Marketing requirements should shape technical decisions, not fight them
- "Done" is a myth — plan for iteration from the start
1. SEO Is an Architecture Decision, Not a Checklist
Most teams treat SEO like something you sprinkle on after launch — meta tags, a sitemap, maybe some alt text if there's time.
That's backwards.
Things like server-side rendering vs. client-side rendering, URL structure, and how you handle canonical tags aren't cosmetic — they determine whether your app is even crawlable in a useful way. Retrofitting SSR onto a fully client-rendered SPA six months post-launch is painful and expensive compared to deciding it upfront.
// Deciding this on day one:
export async function getServerSideProps(context) {
// vs. client-only rendering that search engines
// may index poorly or with a delay
}
If your app's core value depends on organic discovery, this decision belongs in your first sprint, not your backlog.
2. Set a Performance Budget and Actually Enforce It
"We'll optimize later" is one of the most common last words in software.
We started attaching hard performance budgets to CI:
# lighthouse-ci config, roughly
assertions:
first-contentful-paint:
max: 2000ms
total-blocking-time:
max: 300ms
If a PR blows the budget, it fails CI. No debate, no "we'll fix it next sprint." This one change did more for our Core Web Vitals than any individual optimization sprint ever did.
3. Decouple Early, Even If It Feels Like Overkill
Tightly coupling frontend and backend feels faster in the first two weeks and painfully slower every week after that.
A clean API boundary means:
- Marketing landing pages can ship independently of the core app
- A/B tests don't require touching backend logic
- Mobile clients (if they ever happen) aren't a rewrite
/api/v1/* → backend, versioned, stable contract
/app/* → core product frontend
/marketing/* → campaign pages, can deploy on its own cadence
This isn't microservices dogma — plenty of monoliths are fine. It's specifically about not letting your marketing site's release cycle be hostage to your app's release cycle.
4. Let Marketing Requirements Shape Technical Decisions (Seriously)
This one goes against a lot of engineering instinct, but hear me out.
If growth/marketing needs UTM-based attribution, fast-loading landing pages, or specific structured data for rich snippets, those aren't "their problem to figure out after launch." They're inputs into your technical spec, same as any other requirement.
Teams that treat marketing needs as an afterthought end up doing expensive rework — bolting on tracking scripts, restructuring routes for campaign pages, or rebuilding meta tag systems after the fact. Teams that bring marketing into planning early bake this in cheaply.
5. "Done" Is a Myth — Design for Iteration
The apps that age well aren't the ones that got everything right at launch. They're the ones built to be changed without dread.
Practically, that means:
- Feature flags over big-bang releases
- Config-driven content where possible (so non-engineers can tweak copy/CTAs without a deploy)
- Logging and analytics wired in from day one, not added when someone finally asks "wait, do we know if this feature is even used?"
if (featureFlags.newOnboardingFlow) {
return <NewOnboarding />;
}
return <LegacyOnboarding />;
Small thing. Huge payoff over a year of shipping.
Closing Thought
None of this is revolutionary. Most of it is "well, obviously" in hindsight. But the number of projects that skip these basics — because of deadline pressure, siloed teams, or just not thinking about it upfront — is higher than it should be.
If there's one takeaway: treat growth and performance as first-class technical requirements, not afterthoughts. Your future self (and your on-call rotation) will thank you.
We build and scale web apps at iNext ETS — happy to swap war stories if you're working through similar problems.
Top comments (0)