Jeg har efterhånden accepteret, at jeg ikke er den udvikler, der bygger ting på den teknisk mest elegante måde, hvis elegant betyder “kræver tre whiteboards, en arkitekturtitel og et møde om service boundaries”.
Jeg bygger produkter alene.
Det ændrer alt.
Når man er én person om både idé, design, kode, lancering, fejlrettelser, support og de små mentale sammenbrud, der opstår, når Apple afviser et build af en grund, ingen dødelig burde kende til, begynder man at se anderledes på teknologi.
For mig handler en god stack ikke om at vinde benchmarks. Den handler om at få reelle produkter ud i verden uden at drukne i opsætning, drift og ceremonier. Det er derfor, jeg primært bygger med React, Vite, Node.js, Tailwind CSS, Capacitor, Firestore og TypeScript.
Ikke fordi det er perfekt. Det er det ikke.
Men fordi det passer til den måde, jeg arbejder på: én person, én kodebase, tre platforme, færrest mulige undskyldninger.
Jeg hedder Halfdan Harring, og jeg bygger produkter fra et skrivebord i Aarhus. Som regel alene. Det er både meget effektivt og en fremragende måde at sikre, at man aldrig kan skyde skylden på “backend-teamet”.
Stacken er valgt til tempo, ikke til konferencetalks
Når jeg starter på et produkt, prøver jeg ikke først at designe den mest fremtidssikrede tekniske konstruktion. Fremtiden har det med at være markant mindre interesseret i mine diagrammer, end jeg kunne ønske mig.
Jeg prøver i stedet at svare på et kedeligt spørgsmål:
Hvor hurtigt kan jeg komme fra idé til noget, der virker for rigtige brugere?
Det spørgsmål har betydet mere for min stack end noget andet.
Quiz Fight, HeadToHead, TaskMondo og LostLead er forskellige produkter. Trivia, football predictions, workspace, AI lead recovery. På papiret burde de måske have haft hver deres særligt udvalgte arkitektur, nøje tilpasset domænet og drysset med lidt teknisk selvtillid.
I praksis har de alle haft samme grundidé under motorhjelmen: React, TypeScript, Firestore og en måde at få det hele ud på web, iOS og Android uden at bygge tre separate produkter.
Det er ikke glamourøst. Det er produktivt.
Og produktivt vinder oftere, end vi bryder os om at indrømme.
Ét sprog i hovedet er en undervurderet luksus
TypeScript, React og Node.js giver mig én meget konkret fordel: Jeg skal ikke skifte mentalt gear hele tiden.
Jeg kan skrive frontend, backend-logik, scripts, helpers og små interne værktøjer i samme sprog og med nogenlunde samme måde at tænke på. Når man arbejder i et team, kan man specialisere sig. Når man arbejder alene, bliver specialisering hurtigt til “endnu en ting jeg skal huske på kl. 23.41, mens barnet sover og deployment fejler”.
JavaScript-verdenen kan sagtens være rodet. Den kan også være lidt som et supermarked, hvor alle hylder er flyttet rundt hver tirsdag. Men økosystemet er enormt, og den viden, jeg opbygger ét sted, kan jeg bruge et andet sted.
React-komponenter, TypeScript-typer, validering, data shapes, API-kald, state, build-scripts. Det hele hænger sammen.
TypeScript er især blevet en af de ting, jeg nødigt vil undvære. Ikke fordi typer gør mig til et bedre menneske. Det skib er sejlet. Men fordi typer fanger mine fejl, før brugerne gør.
Og jeg laver fejl.
Plenty, som briterne ville sige, inden de diskret forlod rummet.
Når jeg arbejder på noget som TaskMondo, hvor mange dele af produktet skal tale sammen, hjælper TypeScript mig med at holde styr på formen af data. Når jeg bygger LostLead og skal flytte information gennem flere trin i et flow, er det rart, at min editor råber op, før produktionen gør.
Det er ikke en garanti mod dumheder. Men det er et ret fint sikkerhedsnet.
Vite holder feedback-loopet kort
Jeg har ikke brug for en build-proces, der føles som en kommunal sagsbehandling.
Vite er en af de teknologier, jeg sætter pris på, netop fordi den ikke fylder så meget i hverdagen. Dev-serveren starter hurtigt. Hot reload føles hurtigt. Builds er hurtige nok til, at jeg ikke når at begynde på noget andet og derefter glemmer, hvad jeg egentlig var i gang med.
Det lyder banalt, men et hurtigt feedback-loop ændrer måden, man bygger på.
Når jeg kan ændre en komponent, se resultatet med det samme, justere spacing, rette flowet, ændre copy og teste igen uden friktion, bliver jeg ved produktet. Jeg bliver i rytmen.
Det betyder meget, når der ikke sidder et team omkring mig og holder processen varm. Der er kun mig og en liste af ting, der alle sammen synes, de er vigtigst.
Vite gør bare sit arbejde. Diskret. Effektivt. Lidt som den kollega, man først opdager værdien af, når de holder ferie.
Tailwind er design uden rundkredsen
Jeg kan godt lide design. Jeg kan også godt lide ikke at bruge tre kvarter på at navngive en CSS-klasse.
Tailwind passer til mig, fordi jeg designer direkte i markup. Jeg kan bygge en skærm, justere den, teste den, flytte ting, ændre responsiv adfærd og lande på noget brugbart uden at hoppe mellem filer hele tiden.
Det er ikke fordi Tailwind automatisk giver godt design. Det gør det ikke. Man kan sagtens bygge noget hæsligt med Tailwind. Faktisk ret hurtigt, hvilket jo også er en slags effektivitet.
Men Tailwind giver mig en ramme for spacing, farver, størrelser og layout, der gør det nemmere at være konsistent. Især på produkter som Quiz Fight og HeadToHead, hvor mange skærme skal føles som del af samme produkt, men stadig kunne justeres hurtigt.
Når jeg bygger solo, er beslutningstræthed en reel fjende. Hver lille beslutning koster. Tailwind fjerner en del af dem. Ikke alle. Der er stadig rigeligt tilbage, bare rolig.
Capacitor er nøglen til hele min måde at bygge på
Capacitor er måske den vigtigste brik i min stack.
Ikke fordi den er mest teknisk imponerende. Men fordi den gør min arbejdsmodel mulig.
Jeg kan bygge én React-app og pakke den som web, iOS og Android. Det betyder, at samme produktlogik, samme UI, samme flows og samme mentale model kan ende på tre platforme uden at jeg skal vedligeholde tre kodebaser.
Det er ikke en lille ting. Det er forskellen på “jeg kan faktisk lancere det her alene” og “jeg bør nok finde et team, en investering og en grund til at holde flere statusmøder”.
Quiz Fight er et godt eksempel. En iOS trivia-app med mere end 500.000 AI-genererede spørgsmål lyder som noget, der hurtigt kunne blive tungt at arbejde med, hvis hver platform havde sin egen kodebase. Men med Capacitor kan jeg holde fokus på selve produktet: spillet, flowet, spørgsmålene, oplevelsen.
Det samme gælder HeadToHead. Football-prediction som produkt handler om tempo, spilforståelse, brugerflows og en oplevelse, der ikke føles som et regneark med fanfarer. Når jeg kan bygge det meste én gang, kan jeg bruge mere tid på produktet og mindre tid på platform-administration.
Capacitor er ikke “ægte native” i den klassiske forstand. Det skal man være ærlig om. Hvis man bygger noget, der kræver ekstremt avanceret native performance, tung grafik eller dyb platformsspecifik integration, kan en webview-baseret tilgang begynde at knirke.
Men til mange produkter er det mere end godt nok. Og “mere end godt nok” er en undervurderet teknisk strategi.
Især når alternativet er aldrig at lancere.
Firestore lader mig slippe for at være mit eget driftsteam
Jeg holder meget af backend-udvikling. Jeg holder mindre af at babysitte infrastruktur.
Firestore passer godt til mig, fordi jeg kan komme hurtigt i gang med realtime data, auth-nære flows og serverless struktur uden først at bygge en klassisk backend, database, hosting, deployment, scaling og alt det andet, der har det med at formere sig i mørke.
Det betyder ikke, at Firestore er gratis magi. Det er det absolut ikke. Men det betyder, at jeg som solo-builder kan springe et helt lag af drift over og komme hurtigere frem til produktspørgsmålet:
Virker det her for brugerne?
På LostLead giver det mening at kunne prototype hurtigt og lade infrastrukturen være forholdsvis usynlig. På TaskMondo gør realtime-egenskaberne det lettere at bygge en oplevelse, hvor ændringer føles levende uden at jeg skal opfinde min egen synkroniseringsmotor. Gudskelov for det. Der er grænser for, hvor meget karakteropbygning et menneske har brug for.
Firestore skalerer på en måde, der er rar, når man ikke har lyst til at oprette et internt DevOps-departement bestående af sig selv i en anden hættetrøje.
Men der er trade-offs. Dem kommer vi til.
Den røde tråd: fjern alt det, der ikke er produktet
Når jeg kigger på min stack, ser jeg ikke syv teknologier. Jeg ser syv måder at fjerne arbejde på.
TypeScript fjerner en del dumme fejl. React fjerner friktion i UI-arbejdet. Node fjerner sprogskift. Vite fjerner ventetid. Tailwind fjerner CSS-omveje. Capacitor fjerner tre separate platformsteams. Firestore fjerner en stor del infrastrukturarbejde.
Det er ikke fordi arbejde i sig selv er dårligt. Jeg kan sagtens lide at nørde. Problemet er bare, at tid brugt på at polere arkitektur ofte bliver taget direkte fra tid brugt på produktet.
Og når man bygger alene, er timerne brutalt ærlige.
Der er ingen, der kommer og tager over. Ingen designer, der lige fikser flowet. Ingen backend-udvikler, der lige skriver migrationen. Ingen QA-afdeling, der fanger det mærkelige edge case på Android, hvor alt ser fint ud, bortset fra det hele.
Det er mig.
Det gælder også hver eneste bug, som jeg vist har nævnt før. Det tåler desværre gentagelse.
Jeg har skrevet mere om min måde at bygge ting fra idé til produkt på om-siden. Og hvis du vil længere ned i, hvordan jeg bruger moderne AI-værktøjer i udviklingsarbejdet, passer Vibe coding i virkeligheden og valg af AI-model i Cursor fint sammen med den her stack.
Det er en kedelig stack. Det er en del af pointen.
Jeg vælger ikke stack efter, hvad der ser mest interessant ud på Hacker News i den uge.
Det kan ellers være fristende. Der er altid et nyt framework, en ny runtime, en ny database, en ny måde at gøre routing på, og en ny person på internettet, der forklarer, at alt det gamle er dødt.
Det gamle er sjældent dødt. Det har bare fået færre launch posts.
Min stack er relativt kedelig. React er ikke nyt. Node er ikke nyt. TypeScript er efterhånden almindelig husholdning. Tailwind har været igennem sin hypefase og står stadig. Firestore og Capacitor er ikke eksotiske valg.
Det passer mig glimrende.
Kedeligt betyder, at der findes dokumentation. Kedeligt betyder, at andre har haft de samme problemer før mig. Kedeligt betyder, at Stack Overflow, GitHub issues og et par mørke Reddit-tråde som regel kan få mig videre.
Når jeg bygger produkter, har jeg ikke brug for at være first mover på værktøjer. Jeg vil hellere være tidligt ude med selve produktet.
Det er en væsentlig forskel.
De ærlige trade-offs
Der er selvfølgelig en pris.
Firestore kan bide. Query-modellen kræver, at man tænker anderledes end i en klassisk relationel database. Man modellerer efter læsemønstre, ikke efter hvad der føles pænt i et ER-diagram. Det kan være hurtigt og effektivt, men det kan også blive bøvlet, hvis produktet ændrer form.
Omkostningerne kan også overraske, hvis man ikke tænker sig om. Firestore belønner ikke nødvendigvis den naive løsning, hvor man bare læser alt hele tiden og håber, at Google sender en sympatisk faktura. Det gør de sjældent.
Capacitor har også grænser. Det føles ikke altid som en app bygget 100 procent native fra bunden, fordi det netop ikke er det. Man skal acceptere de steder, hvor web og native mødes lidt akavet i døren. Plugins, platformsspecifik adfærd og app store-krav kan stadig give små fine hovedpiner.
Firebase lock-in er reel. Når man bygger tæt på Firestore, auth og resten af Firebase-økosystemet, er det ikke gratis at flytte væk. Man kan godt. Men man gør det ikke en onsdag efter frokost, fordi man lige fik en frisk idé.
Og så er der prisen ved at vælge det kedelige. Man går glip af noget. Nye værktøjer kan være bedre. Hurtigere. Smukkere. Mere gennemtænkte. Hvis man altid vælger det gennemprøvede, kan man blive lidt for komfortabel.
Det prøver jeg at være opmærksom på.
Men for mig er spørgsmålet ikke: “Hvad er den bedste stack?”
Det er: “Hvad er den bedste stack til en person, der skal bygge, lancere og drive produktet selv?”
Det svar ændrer regnestykket.
Den rigtige stack er den, der passer til arbejdet
Jeg ville ikke anbefale min stack til alle.
Et stort enterprise-team med tunge compliance-krav, avanceret domænelogik og mange specialiserede teams bør sandsynligvis træffe andre valg. En tung 3D-app bør nok heller ikke starte med “hvad nu hvis vi bare pakkede en webapp ind?”
Men til min måde at arbejde på giver stacken mening.
Jeg kan få en idé, skitsere produktet, bygge første version, teste flowet, lancere på flere platforme og iterere uden at skulle samle et hold først. Det er den centrale fordel. Ikke at stacken er smart. Ikke at den er moderne. Ikke at den vinder diskussionen på LinkedIn blandt mennesker, der har “thought leader” i bio.
Den gør mig i stand til at sende ting ud.
Og det er hele pointen.
For mig er tech stack ikke en identitet. Det er værktøj. En ret vigtig værktøjskasse, ja, men stadig en værktøjskasse. Hvis den hjælper mig med at bygge Quiz Fight, HeadToHead, TaskMondo og LostLead hurtigere og med færre lag af unødvendigt arbejde, så er den god.
Ikke perfekt. Bare god.
Hvilket også beskriver det meste af solid software, når man ser ærligt på det.
Nu skal jeg bare huske at opdatere dependencies, før de bliver arkæologi. Og måske se The Office igen fra starten, mens jeg venter på næste build. Helt almindelig søndag.