← Notes

La stack 2026 pour créer une app, sans s'arracher les cheveux

· stack · indie · mobile · 6 min · EN

Ma première app m’a pris beaucoup plus de temps que ma troisième. Le delta n’est pas dans ma vitesse de frappe : il est dans le choix de stack.

Voici la stack avec laquelle je referais une app solo demain matin, les anti-patterns que j’ai vécus en chemin, et les pièges concrets qui ne sont pas dans la doc.

La règle qui sous-tend tout

Tu codes pendant 6 semaines, ou tu codes pendant 4 mois. La différence ne se joue pas sur ta vitesse de frappe.

Elle se joue sur :

  • Combien de temps tu passes à débugger des certificats Apple, des webhooks Stripe, ou de l’auth maison.
  • Combien de fois tu refais la même infra parce que ton choix précédent ne tient pas.
  • Combien de bibliothèques tu intègres “qui font la même chose en mieux”.

Tout ce qui suit est optimisé pour minimiser ces trois pertes.

Mobile : Expo, et oublie React Native bare

npx create-expo-app my-app --template blank-typescript

Pas de “ejection précoce”. Pas de RN bare. Tu démarres en Expo Go pour le proto, puis en dev build dès que tu touches à un module natif (react-native-purchases, expo-av en config avancée).

Ce que ça t’évite concrètement : EAS Build te sort un IPA prêt pour TestFlight en quelques minutes. À la main, c’est plusieurs jours à comprendre fastlane, les certificats, les profils de provisioning et le système Apple. Plus jamais à la main.

Le piège : si tu ejectes (build natif custom), tu perds les updates OTA Expo. Garde l’ejection pour la dernière ressource, et seulement si vraiment aucun module ne couvre ton besoin.

Flutter ? Très bon framework. Mais l’écosystème JS me permet de partager des types et des prompts IA entre mobile et web — ce qui réduit la friction quand j’ai un backend Edge Function commun. Stack unifiée TS partout = moins de charge mentale.

Backend : Supabase Edge Functions, et basta

Postgres managé + auth + RLS + Edge Functions Deno. Tout dans le même dashboard.

Voici un endpoint typique (l’analyse vocale de VoiceJournal) :

// supabase/functions/analyze-entry/index.ts
Deno.serve(async (req) => {
  const token = req.headers.get("Authorization")?.replace("Bearer ", "");
  const { data: { user } } = await supabase.auth.getUser(token);
  if (!user) return new Response("Unauthorized", { status: 401 });

  const transcript = await openai.audio.transcriptions.create({
    file: audioFile, model: "whisper-1", language: "fr",
  });

  const analysis = await anthropic.messages.create({
    model: "claude-sonnet-4-6",
    max_tokens: 1024,
    messages: [{ role: "user", content: buildPrompt(transcript.text) }],
  });

  return Response.json({ entry: parseAnalysis(analysis) });
});

Pas de serveur qui dort en coûtant des sous. Tu paies à l’invocation.

Le piège : les Edge Functions ont un cold-start non-négligeable (autour de 100-200ms). Pour un endpoint IA qui prend plusieurs secondes côté LLM, c’est invisible. Pour un endpoint qui doit répondre instantanément, ça commence à compter. À toi de voir si tu as ce type d’endpoint.

Firebase ? Verrouillé, NoSQL pénible dès que ton modèle devient relationnel, pricing imprévisible. Postgres + RLS > Firestore + security rules à chaque fois.

IA : choisis ton modèle par endpoint, pas par projet

C’est la leçon la plus utile que j’ai apprise. Le bon modèle dépend de l’endpoint, pas de l’app.

Sur VoiceJournal :

  • Transcription audio → Whisper (OpenAI). Spécialisé audio, plus rapide que Claude qui ne traite pas vraiment l’audio.
  • Analyse fine d’une entrée → Claude Sonnet 4.6. Meilleure compréhension du français, sortie JSON propre, suit bien un prompt structuré.
  • Classification d’émotions en bulk → Gemini Flash. Moins cher quand la qualité requise est moyenne et le volume élevé.

J’ai un util lib/llm.ts qui expose analyzeWithClaude, transcribeWithWhisper, classifyWithGemini. Si demain un meilleur modèle sort, je change une constante. Ne te lock pas sur un seul provider.

Subscriptions : RevenueCat dès le jour 1

Gérer toi-même StoreKit (iOS) + Billing API (Android) en solo, c’est plusieurs semaines de boilerplate. Avec RevenueCat, c’est une après-midi.

Le piège pas évident : tu dois appeler Purchases.logIn(supabase_user_id) après le login Supabase, et Purchases.logOut() au logout. Sans ça, les webhooks RevenueCat envoient un mauvais app_user_id à ta backend et tu ne peux pas synchroniser le statut Pro côté base. La doc ne le crie pas assez fort.

// Après auth Supabase
await Purchases.logIn(user.id);

Tarif : gratuit jusqu’à un seuil de MRR au-delà duquel un pourcentage s’applique. Pas un sujet tant que tu démarres.

Web : Astro, pas Next.js

Pour une landing, un blog, un portfolio : Next.js est trop lourd. Astro génère du HTML statique, zéro JS par défaut, intègre Tailwind 4 nativement, gère i18n et content collections.

Le site que tu lis tourne sur Astro 6. Déploiement gratuit sur GitHub Pages.

Next.js, quand ? Si tu as besoin de SSR (auth-gated, data réelle au render), de API routes en TS partagées, ou que tu fais un produit web complexe. Pour une landing ou un blog : surdimensionné.

State mobile : Zustand, point.

import { create } from "zustand";

export const useAuthStore = create<AuthState>((set) => ({
  user: null,
  setUser: (user) => set({ user }),
}));

1 KB. Zéro provider à wrapper. API hook propre. Tous mes besoins de state global passent dedans.

Redux ? Mort pour le solo dev. Trop de boilerplate, et 90% de tes states sont locaux (useState).

Ce que j’ai testé et que j’ai abandonné

TechnoPourquoi je l’avais prisePourquoi je l’ai virée
FirebaseTout intégré, gratuitPricing imprévisible, NoSQL douloureux quand le modèle devient relationnel
Backend Node “sérieux""Vraie” backendEdge Functions font le même boulot en 30 lignes et 0 €/mois
OpenAI GPT-4 par défautC’est ce que tout le monde utilisaitClaude rend mieux sur les tâches que je fais, Gemini classe pour moins cher
MobXVu sur des projets proTrop magique, Zustand fait 1 KB et c’est explicite

La seule règle à retenir

Tu ne valides pas une techno parce qu’elle est tendance, ni parce que tu la connais. Tu la valides parce qu’elle te fait gagner du temps sur ce que tu sais déjà faire et qu’elle ne te coûte rien tant que personne n’utilise ton app.

Cette stack coche les deux. Recopie-la, ship en quelques semaines, et passe à autre chose.