diff --git a/create-app.ts b/create-app.ts
index a0d437010b0b1499e5ee2d1f3ea987f7ea7cf713..2725e3d9f5695126313d90407fe457465f9aa904 100644
--- a/create-app.ts
+++ b/create-app.ts
@@ -34,7 +34,7 @@ export async function createApp({
   communityProjectPath,
   vectorDb,
   externalPort,
-  installDependencies,
+  postInstallAction,
 }: InstallAppArgs): Promise<void> {
   const root = path.resolve(appPath);
 
@@ -76,7 +76,7 @@ export async function createApp({
     communityProjectPath,
     vectorDb,
     externalPort,
-    installDependencies,
+    postInstallAction,
   };
 
   if (frontend) {
diff --git a/e2e/basic.spec.ts b/e2e/basic.spec.ts
index 3e76f5267859a3ab4bbc0ceab981715734ca6c1d..ee4ba33b64b0006828477a0b5c65edf30a486971 100644
--- a/e2e/basic.spec.ts
+++ b/e2e/basic.spec.ts
@@ -9,7 +9,7 @@ import type {
   TemplateType,
   TemplateUI,
 } from "../helpers";
-import { createTestDir, runApp, runCreateLlama, type AppType } from "./utils";
+import { createTestDir, runCreateLlama, type AppType } from "./utils";
 
 const templateTypes: TemplateType[] = ["streaming", "simple"];
 const templateFrameworks: TemplateFramework[] = [
@@ -47,27 +47,26 @@ for (const templateType of templateTypes) {
           let externalPort: number;
           let cwd: string;
           let name: string;
-          let cps: ChildProcess[] = [];
+          let appProcess: ChildProcess;
+          const postInstallAction = "runApp";
 
           test.beforeAll(async () => {
             port = Math.floor(Math.random() * 10000) + 10000;
             externalPort = port + 1;
-
             cwd = await createTestDir();
-            name = runCreateLlama(
+            const result = await runCreateLlama(
               cwd,
               templateType,
               templateFramework,
               templateEngine,
               templateUI,
               appType,
+              port,
               externalPort,
+              postInstallAction,
             );
-
-            if (templateFramework !== "fastapi") {
-              // don't run the app for fastapi for now (adds python dependency)
-              cps = await runApp(cwd, name, appType, port, externalPort);
-            }
+            name = result.projectName;
+            appProcess = result.appProcess;
           });
 
           test("App folder should exist", async () => {
@@ -75,9 +74,7 @@ for (const templateType of templateTypes) {
             expect(dirExists).toBeTruthy();
           });
           test("Frontend should have a title", async ({ page }) => {
-            test.skip(
-              appType === "--no-frontend" || templateFramework === "fastapi",
-            );
+            test.skip(appType === "--no-frontend");
             await page.goto(`http://localhost:${port}`);
             await expect(page.getByText("Built by LlamaIndex")).toBeVisible();
           });
@@ -85,9 +82,7 @@ for (const templateType of templateTypes) {
           test("Frontend should be able to submit a message and receive a response", async ({
             page,
           }) => {
-            test.skip(
-              appType === "--no-frontend" || templateFramework === "fastapi",
-            );
+            test.skip(appType === "--no-frontend");
             await page.goto(`http://localhost:${port}`);
             await page.fill("form input", "hello");
             await page.click("form button[type=submit]");
@@ -107,11 +102,10 @@ for (const templateType of templateTypes) {
           test("Backend should response when calling API", async ({
             request,
           }) => {
-            test.skip(
-              appType !== "--no-frontend" || templateFramework === "fastapi",
-            );
+            test.skip(appType !== "--no-frontend");
+            const backendPort = appType === "" ? port : externalPort;
             const response = await request.post(
-              `http://localhost:${port}/api/chat`,
+              `http://localhost:${backendPort}/api/chat`,
               {
                 data: {
                   messages: [
@@ -130,7 +124,7 @@ for (const templateType of templateTypes) {
 
           // clean processes
           test.afterAll(async () => {
-            cps.map((cp) => cp.kill());
+            appProcess.kill();
           });
         });
       }
diff --git a/e2e/utils.ts b/e2e/utils.ts
index ac291e9adb49ecc11706cfe915d655a11ea60d23..9e2c8ddee97f20d0bd3f0720f1e79e7690867c52 100644
--- a/e2e/utils.ts
+++ b/e2e/utils.ts
@@ -1,81 +1,77 @@
-import { ChildProcess, exec, execSync } from "child_process";
+import { ChildProcess, exec } from "child_process";
 import crypto from "node:crypto";
 import { mkdir } from "node:fs/promises";
 import * as path from "path";
 import waitPort from "wait-port";
+import {
+  TemplateEngine,
+  TemplateFramework,
+  TemplatePostInstallAction,
+  TemplateType,
+  TemplateUI,
+} from "../helpers";
 
 export type AppType = "--frontend" | "--no-frontend" | "";
 const MODEL = "gpt-3.5-turbo";
+export type CreateLlamaResult = {
+  projectName: string;
+  appProcess: ChildProcess;
+};
 
 // eslint-disable-next-line max-params
-export async function runApp(
-  cwd: string,
-  name: string,
-  appType: AppType,
+export async function checkAppHasStarted(
+  frontend: boolean,
+  framework: TemplateFramework,
   port: number,
   externalPort: number,
-): Promise<ChildProcess[]> {
-  const cps: ChildProcess[] = [];
-
-  try {
-    switch (appType) {
-      case "--frontend":
-        cps.push(
-          await createProcess(
-            "npm run dev",
-            path.join(cwd, name, "backend"),
-            externalPort,
-          ),
-        );
-        cps.push(
-          await createProcess(
-            "npm run dev",
-            path.join(cwd, name, "frontend"),
-            port,
-          ),
-        );
-        break;
-      default:
-        cps.push(
-          await createProcess("npm run dev", path.join(cwd, name), port),
-        );
-        break;
+  timeout: number,
+) {
+  if (frontend) {
+    await Promise.all([
+      waitPort({
+        host: "localhost",
+        port: port,
+        timeout,
+      }),
+      waitPort({
+        host: "localhost",
+        port: externalPort,
+        timeout,
+      }),
+    ]).catch((err) => {
+      console.error(err);
+      throw err;
+    });
+  } else {
+    let wPort: number;
+    if (framework === "nextjs") {
+      wPort = port;
+    } else {
+      wPort = externalPort;
     }
-  } catch (e) {
-    cps.forEach((cp) => cp.kill());
-    throw e;
+    await waitPort({
+      host: "localhost",
+      port: wPort,
+      timeout,
+    }).catch((err) => {
+      console.error(err);
+      throw err;
+    });
   }
-  return cps;
-}
-
-async function createProcess(command: string, cwd: string, port: number) {
-  const cp = exec(command, {
-    cwd,
-    env: {
-      ...process.env,
-      PORT: `${port}`,
-    },
-  });
-  if (!cp) throw new Error(`Can't start process ${command} in ${cwd}`);
-
-  await waitPort({
-    host: "localhost",
-    port,
-    timeout: 1000 * 60,
-  });
-  return cp;
 }
 
 // eslint-disable-next-line max-params
-export function runCreateLlama(
+export async function runCreateLlama(
   cwd: string,
-  templateType: string,
-  templateFramework: string,
-  templateEngine: string,
-  templateUI: string,
+  templateType: TemplateType,
+  templateFramework: TemplateFramework,
+  templateEngine: TemplateEngine,
+  templateUI: TemplateUI,
   appType: AppType,
+  port: number,
   externalPort: number,
-) {
+  postInstallAction: TemplatePostInstallAction,
+): Promise<CreateLlamaResult> {
   const createLlama = path.join(__dirname, "..", "dist", "index.js");
 
   const name = [
@@ -104,17 +100,43 @@ export function runCreateLlama(
     appType,
     "--eslint",
     "--use-npm",
+    "--port",
+    port,
     "--external-port",
     externalPort,
-    "--install-dependencies",
+    "--post-install-action",
+    postInstallAction,
   ].join(" ");
   console.log(`running command '${command}' in ${cwd}`);
-  execSync(command, {
-    stdio: "inherit",
+  let appProcess = exec(command, {
     cwd,
   });
-  return name;
+  appProcess.on("error", (err) => {
+    console.error(err);
+    appProcess.kill();
+  });
+  // Show log from cp
+  appProcess.stdout?.on("data", (data) => {
+    console.log(data.toString());
+  });
+
+  // Wait for app to start
+  if (postInstallAction === "runApp") {
+    await checkAppHasStarted(
+      appType === "--frontend",
+      templateFramework,
+      port,
+      externalPort,
+      1000 * 60 * 5,
+    );
+  }
+
+  return {
+    projectName: name,
+    appProcess,
+  };
 }
+
 export async function createTestDir() {
   const cwd = path.join(__dirname, ".cache", crypto.randomUUID());
   await mkdir(cwd, { recursive: true });
diff --git a/helpers/python.ts b/helpers/python.ts
index 4b28231013b9252f5a86ffcaa11253e0765daed1..163a2f6ba65cb5e843bd5b2f6551d3917acd072d 100644
--- a/helpers/python.ts
+++ b/helpers/python.ts
@@ -1,6 +1,6 @@
 import fs from "fs/promises";
 import path from "path";
-import { cyan, yellow } from "picocolors";
+import { cyan, red, yellow } from "picocolors";
 import { parse, stringify } from "smol-toml";
 import terminalLink from "terminal-link";
 import { copy } from "./copy";
@@ -92,13 +92,39 @@ export const addDependencies = async (
   }
 };
 
+export const installPythonDependencies = (root: string) => {
+  if (isPoetryAvailable()) {
+    console.log(
+      `Installing python dependencies using poetry. This may take a while...`,
+    );
+    const installSuccessful = tryPoetryInstall();
+    if (!installSuccessful) {
+      console.error(
+        red("Install failed. Please install dependencies manually."),
+      );
+      process.exit(1);
+    }
+  } else {
+    console.warn(
+      yellow(
+        `Poetry is not available in the current environment. The Python dependencies will not be installed automatically.
+Please check ${terminalLink(
+          "Poetry Installation",
+          `https://python-poetry.org/docs/#installation`,
+        )} to install poetry first, then install the dependencies manually.`,
+      ),
+    );
+    process.exit(1);
+  }
+};
+
 export const installPythonTemplate = async ({
   root,
   template,
   framework,
   engine,
   vectorDb,
-  installDependencies,
+  postInstallAction,
 }: Pick<
   InstallTemplateArgs,
   | "root"
@@ -106,7 +132,7 @@ export const installPythonTemplate = async ({
   | "template"
   | "engine"
   | "vectorDb"
-  | "installDependencies"
+  | "postInstallAction"
 >) => {
   console.log("\nInitializing Python project with template:", template, "\n");
   const templatePath = path.join(
@@ -154,28 +180,7 @@ export const installPythonTemplate = async ({
   const addOnDependencies = getAdditionalDependencies(vectorDb);
   await addDependencies(root, addOnDependencies);
 
-  // install python dependencies
-  if (installDependencies) {
-    if (isPoetryAvailable()) {
-      console.log(
-        `Installing python dependencies using poetry. This may take a while...`,
-      );
-      const installSuccessful = tryPoetryInstall();
-      if (!installSuccessful) {
-        console.warn(
-          yellow("Install failed. Please install dependencies manually."),
-        );
-      }
-    } else {
-      console.warn(
-        yellow(
-          `Poetry is not available in the current environment. The Python dependencies will not be installed automatically.
-Please check ${terminalLink(
-            "Poetry Installation",
-            `https://python-poetry.org/docs/#installation`,
-          )} to install poetry first, then install the dependencies manually.`,
-        ),
-      );
-    }
+  if (postInstallAction !== "none") {
+    installPythonDependencies(root);
   }
 };
diff --git a/helpers/run-app.ts b/helpers/run-app.ts
new file mode 100644
index 0000000000000000000000000000000000000000..b77da58bfab133431c6004e9435d551731a4ab76
--- /dev/null
+++ b/helpers/run-app.ts
@@ -0,0 +1,77 @@
+import { ChildProcess, spawn } from "child_process";
+import { log } from "console";
+import path from "path";
+import { TemplateFramework } from "./types";
+
+// eslint-disable-next-line max-params
+export async function runApp(
+  appPath: string,
+  frontend: boolean,
+  framework: TemplateFramework,
+  port?: number,
+  externalPort?: number,
+): Promise<any> {
+  let backendAppProcess: ChildProcess;
+  let frontendAppProcess: ChildProcess | undefined;
+  let frontendPort = port || 3000;
+  let backendPort = externalPort || 8000;
+
+  // Callback to kill app processes
+  const killAppProcesses = () => {
+    log("Killing app processes...");
+    backendAppProcess.kill();
+    frontendAppProcess?.kill();
+  };
+  process.on("exit", () => {
+    killAppProcesses();
+  });
+
+  let backendCommand = "";
+  let backendArgs: string[];
+  if (framework === "fastapi") {
+    backendCommand = "poetry";
+    backendArgs = [
+      "run",
+      "uvicorn",
+      "main:app",
+      "--host=0.0.0.0",
+      "--port=" + (externalPort || backendPort),
+    ];
+  } else if (framework === "nextjs") {
+    backendCommand = "npm";
+    backendArgs = ["run", "dev"];
+    backendPort = frontendPort;
+  } else {
+    backendCommand = "npm";
+    backendArgs = ["run", "dev"];
+  }
+
+  if (frontend) {
+    return new Promise((resolve, reject) => {
+      backendAppProcess = spawn(backendCommand, backendArgs, {
+        stdio: "inherit",
+        cwd: path.join(appPath, "backend"),
+        env: { ...process.env, PORT: `${backendPort}` },
+      });
+      frontendAppProcess = spawn("npm", ["run", "dev"], {
+        stdio: "inherit",
+        cwd: path.join(appPath, "frontend"),
+        env: { ...process.env, PORT: `${frontendPort}` },
+      });
+    }).catch((err) => {
+      console.error(err);
+      killAppProcesses();
+    });
+  } else {
+    return new Promise((resolve, reject) => {
+      backendAppProcess = spawn(backendCommand, backendArgs, {
+        stdio: "inherit",
+        cwd: appPath,
+        env: { ...process.env, PORT: `${backendPort}` },
+      });
+    }).catch((err) => {
+      console.log(err);
+      killAppProcesses();
+    });
+  }
+}
diff --git a/helpers/types.ts b/helpers/types.ts
index 6c85c1c912c52622d027efc3df6ccf49a3b17957..0f28caada8096740234504b8be809d731323ac74 100644
--- a/helpers/types.ts
+++ b/helpers/types.ts
@@ -5,6 +5,7 @@ export type TemplateFramework = "nextjs" | "express" | "fastapi";
 export type TemplateEngine = "simple" | "context";
 export type TemplateUI = "html" | "shadcn";
 export type TemplateVectorDB = "none" | "mongo" | "pg";
+export type TemplatePostInstallAction = "none" | "dependencies" | "runApp";
 
 export interface InstallTemplateArgs {
   appName: string;
@@ -23,5 +24,5 @@ export interface InstallTemplateArgs {
   communityProjectPath?: string;
   vectorDb?: TemplateVectorDB;
   externalPort?: number;
-  installDependencies?: boolean;
+  postInstallAction?: TemplatePostInstallAction;
 }
diff --git a/helpers/typescript.ts b/helpers/typescript.ts
index 81b895042a16958115773d658dd582a8d427b25f..8b138c2117654acdc7ffbe44f85b21f917ad3d3f 100644
--- a/helpers/typescript.ts
+++ b/helpers/typescript.ts
@@ -5,6 +5,7 @@ import { bold, cyan } from "picocolors";
 import { version } from "../../core/package.json";
 import { copy } from "../helpers/copy";
 import { callPackageManager } from "../helpers/install";
+import { PackageManager } from "./get-pkg-manager";
 import { InstallTemplateArgs } from "./types";
 
 const rename = (name: string) => {
@@ -23,6 +24,28 @@ const rename = (name: string) => {
     }
   }
 };
+
+export const installTSDependencies = async (
+  packageJson: any,
+  packageManager: PackageManager,
+  isOnline: boolean,
+): Promise<void> => {
+  console.log("\nInstalling dependencies:");
+  for (const dependency in packageJson.dependencies)
+    console.log(`- ${cyan(dependency)}`);
+
+  console.log("\nInstalling devDependencies:");
+  for (const dependency in packageJson.devDependencies)
+    console.log(`- ${cyan(dependency)}`);
+
+  console.log();
+
+  await callPackageManager(packageManager, isOnline).catch((error) => {
+    console.error("Failed to install TS dependencies. Exiting...");
+    process.exit(1);
+  });
+};
+
 /**
  * Install a LlamaIndex internal template to a given `root` directory.
  */
@@ -39,7 +62,7 @@ export const installTSTemplate = async ({
   customApiPath,
   forBackend,
   vectorDb,
-  installDependencies,
+  postInstallAction,
 }: InstallTemplateArgs) => {
   console.log(bold(`Using ${packageManager}.`));
 
@@ -211,17 +234,7 @@ export const installTSTemplate = async ({
     JSON.stringify(packageJson, null, 2) + os.EOL,
   );
 
-  if (installDependencies) {
-    console.log("\nInstalling dependencies:");
-    for (const dependency in packageJson.dependencies)
-      console.log(`- ${cyan(dependency)}`);
-
-    console.log("\nInstalling devDependencies:");
-    for (const dependency in packageJson.devDependencies)
-      console.log(`- ${cyan(dependency)}`);
-
-    console.log();
-
-    await callPackageManager(packageManager, isOnline);
+  if (postInstallAction !== "none") {
+    await installTSDependencies(packageJson, packageManager, isOnline);
   }
 };
diff --git a/index.ts b/index.ts
index 4be39f65f63aebdb13c6c41653c25223950791dc..fae221f24c2123d804650382c1a3f5399ec7d778 100644
--- a/index.ts
+++ b/index.ts
@@ -10,6 +10,7 @@ import checkForUpdate from "update-check";
 import { createApp } from "./create-app";
 import { getPkgManager } from "./helpers/get-pkg-manager";
 import { isFolderEmpty } from "./helpers/is-folder-empty";
+import { runApp } from "./helpers/run-app";
 import { validateNpmName } from "./helpers/validate-pkg";
 import packageJson from "./package.json";
 import { QuestionArgs, askQuestions, onPromptState } from "./questions";
@@ -110,20 +111,27 @@ const program = new Commander.Command(packageJson.name)
     `
 
   Select OpenAI model to use. E.g. gpt-3.5-turbo.
+`,
+  )
+  .option(
+    "--port <port>",
+    `
+
+  Select UI port.
 `,
   )
   .option(
     "--external-port <external>",
     `
 
-Select external port.
+  Select external port.
 `,
   )
   .option(
-    "--install-dependencies",
+    "--post-install-action <action>",
     `
 
-Whether install dependencies (backend/frontend) automatically or not.
+  Choose an action after installation. For example, 'runApp' or 'dependencies'. The default option is just to generate the app.
 `,
   )
   .allowUnknownOption()
@@ -231,9 +239,20 @@ async function run(): Promise<void> {
     communityProjectPath: program.communityProjectPath,
     vectorDb: program.vectorDb,
     externalPort: program.externalPort,
-    installDependencies: program.installDependencies,
+    postInstallAction: program.postInstallAction,
   });
   conf.set("preferences", preferences);
+
+  if (program.postInstallAction === "runApp") {
+    console.log("Running app...");
+    await runApp(
+      root,
+      program.frontend,
+      program.framework,
+      program.port,
+      program.externalPort,
+    );
+  }
 }
 
 const update = checkForUpdate(packageJson).catch(() => null);
diff --git a/questions.ts b/questions.ts
index c6fd984aae27d7ee6f4c7b7f3fcc24c3db52228f..90c87d42998eed0c93bbc3bdf5b081090e378de7 100644
--- a/questions.ts
+++ b/questions.ts
@@ -20,6 +20,7 @@ const defaults: QuestionArgs = {
   openAiKey: "",
   model: "gpt-3.5-turbo",
   communityProjectPath: "",
+  postInstallAction: "dependencies",
 };
 
 const handlers = {
@@ -39,9 +40,9 @@ const getVectorDbChoices = (framework: TemplateFramework) => {
     { title: "PostgreSQL", value: "pg" },
   ];
 
-  const vectodbLang = framework === "fastapi" ? "python" : "typescript";
+  const vectordbLang = framework === "fastapi" ? "python" : "typescript";
   const compPath = path.join(__dirname, "..", "templates", "components");
-  const vectordbPath = path.join(compPath, "vectordbs", vectodbLang);
+  const vectordbPath = path.join(compPath, "vectordbs", vectordbLang);
 
   const availableChoices = fs
     .readdirSync(vectordbPath)
@@ -211,19 +212,6 @@ export const askQuestions = async (
     }
   }
 
-  if (program.installDependencies === undefined) {
-    const { installDependencies } = await prompts({
-      onState: onPromptState,
-      type: "toggle",
-      name: "installDependencies",
-      message: `Would you like to install dependencies automatically? This may take a while`,
-      initial: getPrefOrDefault("installDependencies"),
-      active: "Yes",
-      inactive: "No",
-    });
-    program.installDependencies = Boolean(installDependencies);
-  }
-
   if (!program.model) {
     if (ciInfo.isCI) {
       program.model = getPrefOrDefault("model");
@@ -326,6 +314,46 @@ export const askQuestions = async (
     }
   }
 
+  // Ask for next action after installation
+  if (program.postInstallAction === undefined) {
+    if (ciInfo.isCI) {
+      program.postInstallAction = getPrefOrDefault("postInstallAction");
+    } else {
+      let actionChoices = [
+        {
+          title: "Just generate code (~1 sec)",
+          value: "none",
+        },
+        {
+          title: "Generate code and install dependencies (~2 min)",
+          value: "dependencies",
+        },
+      ];
+
+      const hasOpenAiKey = program.openAiKey || process.env["OPENAI_API_KEY"];
+      if (program.vectorDb === "none" && hasOpenAiKey) {
+        actionChoices.push({
+          title:
+            "Generate code, install dependencies, and run the app (~2 min)",
+          value: "runApp",
+        });
+      }
+
+      const { action } = await prompts(
+        {
+          type: "select",
+          name: "action",
+          message: "How would you like to proceed?",
+          choices: actionChoices,
+          initial: 1,
+        },
+        handlers,
+      );
+
+      program.postInstallAction = action;
+    }
+  }
+
   // TODO: consider using zod to validate the input (doesn't work like this as not every option is required)
   // templateUISchema.parse(program.ui);
   // templateEngineSchema.parse(program.engine);
diff --git a/templates/types/simple/express/package.json b/templates/types/simple/express/package.json
index 849261e4a23743e193c97b3482be5b45f6e7f1f4..b323f2f1c70fb69c26cc78590d57a493b8261ca1 100644
--- a/templates/types/simple/express/package.json
+++ b/templates/types/simple/express/package.json
@@ -14,6 +14,9 @@
     "express": "^4.18.2",
     "llamaindex": "0.0.37"
   },
+  "overrides": {
+    "chromadb": "1.7.3"
+  },
   "devDependencies": {
     "@types/cors": "^2.8.17",
     "@types/express": "^4.17.21",
diff --git a/templates/types/streaming/express/package.json b/templates/types/streaming/express/package.json
index 3e46bb5fb2b427e7d7b1f4cc62b5334aa72437da..db5edf3a9f73f5ac903c1fc6cfd24b2e6e6ca7eb 100644
--- a/templates/types/streaming/express/package.json
+++ b/templates/types/streaming/express/package.json
@@ -15,6 +15,9 @@
     "express": "^4.18.2",
     "llamaindex": "0.0.37"
   },
+  "overrides": {
+    "chromadb": "1.7.3"
+  },
   "devDependencies": {
     "@types/cors": "^2.8.16",
     "@types/express": "^4.17.21",
diff --git a/templates/types/streaming/nextjs/package.json b/templates/types/streaming/nextjs/package.json
index 2f23029ddfba1cefcbf6e1243f19a85f1c2453d0..2683634fdc948ea9994cab7357deb6dd8f256cb5 100644
--- a/templates/types/streaming/nextjs/package.json
+++ b/templates/types/streaming/nextjs/package.json
@@ -27,6 +27,9 @@
     "supports-color": "^9.4.0",
     "tailwind-merge": "^2.1.0"
   },
+  "overrides": {
+    "chromadb": "1.7.3"
+  },
   "devDependencies": {
     "@types/node": "^20.10.3",
     "@types/react": "^18.2.42",