diff --git a/app/betterplace_test.ts b/app/betterplace_test.ts
index dcff85e323e70a6a6f774c6cf5c2d9d335814f66..8d4450f0b61ee6cfaafb6dde0149ea86569531fc 100644
--- a/app/betterplace_test.ts
+++ b/app/betterplace_test.ts
@@ -46,6 +46,13 @@ type UrlPrefix = string;
 const projectsUrlWithDefaultOptions =
   "https://api.betterplace.org/de/api_v4/projects.json?facets=completed%3Afalse%7Cclosed%3Afalse%7Cprohibit_donations%3Afalse&order=rank%3ADESC";
 
+const noCacheServerConfig = {
+  cacheEnabled: false,
+  port: 0,
+  cacheTtlMsBetterplace: 0,
+  fake: false,
+};
+
 const stubFetchByUrlPrefix = (
   responses: Record<UrlPrefix, ResponsePayload>,
 ) => {
@@ -323,7 +330,7 @@ describe("betterplace", () => {
     it("correctly parses project list", async () => {
       fetchStub = stubFetchByUrlPrefix(validApiResponses);
 
-      const graphQLServer = createGraphQLServer({ cacheEnabled: false });
+      const graphQLServer = createGraphQLServer(noCacheServerConfig);
       const result = await queryProjects(graphQLServer);
 
       assertEquals(result, expectedProjectsResponse);
@@ -355,7 +362,7 @@ describe("betterplace", () => {
           new Error("Expected error"),
       });
 
-      const graphQLServer = createGraphQLServer({ cacheEnabled: false });
+      const graphQLServer = createGraphQLServer(noCacheServerConfig);
       const result = await queryProjects(graphQLServer);
 
       const project1 = result.data.find((p) => p.id === 1);
@@ -371,7 +378,7 @@ describe("betterplace", () => {
         ),
       });
 
-      const graphQLServer = createGraphQLServer({ cacheEnabled: false });
+      const graphQLServer = createGraphQLServer(noCacheServerConfig);
       const result = await queryProjects(graphQLServer);
 
       const project1 = result.data.find((p) => p.id === 1);
@@ -390,7 +397,7 @@ describe("betterplace", () => {
         ),
       });
 
-      const graphQLServer = createGraphQLServer({ cacheEnabled: false });
+      const graphQLServer = createGraphQLServer(noCacheServerConfig);
       const result = await queryProjects(graphQLServer);
       const project1 = result.data.find((p) => p.id === 1);
       assertExists(project1);
@@ -399,7 +406,12 @@ describe("betterplace", () => {
 
     it("returns cached results on recurring requests", async () => {
       fetchStub = stubFetchByUrlPrefix(validApiResponses);
-      const graphQLServer = createGraphQLServer({ cacheEnabled: true });
+      const graphQLServer = createGraphQLServer({
+        cacheEnabled: true,
+        port: 0,
+        cacheTtlMsBetterplace: 1000,
+        fake: false,
+      });
       const result = await queryProjects(graphQLServer);
       assertEquals(result, expectedProjectsResponse);
 
@@ -418,7 +430,7 @@ describe("betterplace", () => {
     it("correctly retrieves a project by ID", async () => {
       fetchStub = stubFetchByUrlPrefix(validApiResponses);
 
-      const graphQLServer = createGraphQLServer({ cacheEnabled: false });
+      const graphQLServer = createGraphQLServer(noCacheServerConfig);
       const result = await queryProject(graphQLServer);
 
       assertEquals(result, expectedResult);
@@ -427,7 +439,7 @@ describe("betterplace", () => {
     it("correctly extracts language from locale", async () => {
       fetchStub = stubFetchByUrlPrefix(validApiResponses);
 
-      const graphQLServer = createGraphQLServer({ cacheEnabled: false });
+      const graphQLServer = createGraphQLServer(noCacheServerConfig);
       const result = await queryProject(graphQLServer, {
         "accept-language": "de-DE",
       });
@@ -441,7 +453,7 @@ describe("betterplace", () => {
     it("uses correct language as default if requested language is not supported", async () => {
       fetchStub = stubFetchByUrlPrefix(validApiResponses);
 
-      const graphQLServer = createGraphQLServer({ cacheEnabled: false });
+      const graphQLServer = createGraphQLServer(noCacheServerConfig);
       const result = await queryProject(graphQLServer, {
         "accept-language": "es",
       });
diff --git a/app/main.ts b/app/main.ts
index 7e31c805390d883dfaaa537dd58da4ce4104ee02..e1292f81b7425faf050d9283d188283aec1e7a82 100644
--- a/app/main.ts
+++ b/app/main.ts
@@ -1,5 +1,10 @@
 import { logger, LogSeverity } from "./logging.ts";
-import { startServer } from "./server.ts";
+import {
+  DEFAULT_CACHE_ENABLED,
+  DEFAULT_CACHE_TTL_MS_BETTERPLACE,
+  DEFAULT_PORT,
+  startServer,
+} from "./server.ts";
 
 const environment = Deno.env.get("ENVIRONMENT") || "development";
 
@@ -8,13 +13,35 @@ logger.setUpLogger(
   environment === "development" ? LogSeverity.DEFAULT : LogSeverity.INFO,
 );
 
+const requiredEnv = <T>(
+  name: string,
+  typeFn: (s: string) => T,
+  fallback?: T,
+): T => {
+  const env = Deno.env.get(name);
+  if (env === undefined && fallback === undefined) {
+    throw Error(`Environment variable "${name}" is required`);
+  } else {
+    return env !== undefined ? typeFn(env) : fallback!;
+  }
+};
+
+const asBoolean = (str: string) => /^true$/i.test(str);
+
 const serverConfigFromEnv = () => {
-  const asNumber = (str?: string) => (str ? Number(str) : undefined);
-  const asBoolean = (str?: string) => (str ? Boolean(str) : undefined);
   return {
-    port: asNumber(Deno.env.get("PORT")),
-    cacheEnabled: asBoolean(Deno.env.get("CACHE_ENABLED")),
-    cacheTtlMsBetterplace: asNumber(Deno.env.get("CACHE_TTL_MS_BETTERPLACE")),
+    port: requiredEnv("PORT", Number, DEFAULT_PORT),
+    cacheEnabled: requiredEnv(
+      "CACHE_ENABLED",
+      asBoolean,
+      DEFAULT_CACHE_ENABLED,
+    ),
+    cacheTtlMsBetterplace: requiredEnv(
+      "CACHE_TTL_MS_BETTERPLACE",
+      Number,
+      DEFAULT_CACHE_TTL_MS_BETTERPLACE,
+    ),
+    fake: requiredEnv("FAKE", asBoolean, false), // For local development. If set, the API returns dummy data
   };
 };
 
diff --git a/app/server.ts b/app/server.ts
index 99695972bf8b0ff818548bd6efd4dc00dc942987..75207fbb30133c65d35835712d14a6a694e704b0 100644
--- a/app/server.ts
+++ b/app/server.ts
@@ -1,10 +1,12 @@
 import {
   BetterPlaceLanguage,
   Initiative,
+  News,
   NewsParameters,
   Project,
   ProjectParameters,
   ProjectsParameters,
+  ProjectsResponse,
 } from "./types.ts";
 import {
   DEFAULT_LANGUAGE,
@@ -80,6 +82,31 @@ const typeDefs = `
     }
 `;
 
+const fakeProject: Project = {
+  id: 10,
+  title: "fake",
+  categories: [],
+  city: undefined,
+  country: undefined,
+  initiative: {
+    id: 0,
+    name: "fake",
+    city: undefined,
+    country: undefined,
+    picture: [],
+  },
+  donationsCount: 0,
+  progressPercentage: 0,
+  openAmountInCents: 0,
+  picture: [],
+  summary: undefined,
+  description: undefined,
+  donationUrl: "",
+  newsUrl: "",
+  news: [],
+  newsCount: 0,
+};
+
 const createResolvers = (_config: ServerConfig) => ({
   Query: {
     projects: (
@@ -87,21 +114,29 @@ const createResolvers = (_config: ServerConfig) => ({
       _parent: any,
       parameters: ProjectsParameters = {},
       context: GraphQLContext,
-    ) => fetchProjects(parameters, context.language),
+    ): Promise<ProjectsResponse> =>
+      _config.fake
+        ? Promise.resolve({ totalResults: 0, data: [] })
+        : fetchProjects(parameters, context.language),
     project: (
       // deno-lint-ignore no-explicit-any
       _parent: any,
       parameters: ProjectParameters,
       context: GraphQLContext,
-    ) => fetchProject(parameters, context.language),
+    ): Promise<Project> =>
+      _config.fake
+        ? Promise.resolve(fakeProject)
+        : fetchProject(parameters, context.language),
   },
   Project: {
-    categories: (args: Project) => fetchCategories(args.id),
-    news: (args: Project, parameters: NewsParameters = {}) =>
-      fetchNews(args, parameters),
+    categories: (args: Project): Promise<string[]> =>
+      _config.fake ? Promise.resolve([]) : fetchCategories(args.id),
+    news: (args: Project, parameters: NewsParameters = {}): Promise<News[]> =>
+      _config.fake ? Promise.resolve([]) : fetchNews(args, parameters),
   },
   Initiative: {
-    url: (args: Initiative) => fetchInitiativeUrl(args),
+    url: (args: Initiative): Promise<string | undefined> =>
+      _config.fake ? Promise.resolve(undefined) : fetchInitiativeUrl(args),
   },
 });
 
@@ -110,9 +145,10 @@ export const DEFAULT_CACHE_ENABLED = true;
 export const DEFAULT_CACHE_TTL_MS_BETTERPLACE = 60_000;
 
 export interface ServerConfig {
-  port?: number; // default: 8001
-  cacheEnabled?: boolean; // default: true
-  cacheTtlMsBetterplace?: number; // default: 60 seconds
+  port: number; // default: 8001
+  cacheEnabled: boolean; // default: true
+  cacheTtlMsBetterplace: number; // default: 60 seconds
+  fake: boolean; // For local development. If set, the API returns dummy data
 }
 
 const getLanguage = (languages = "") =>
@@ -123,7 +159,7 @@ const getLanguage = (languages = "") =>
   DEFAULT_LANGUAGE;
 
 export const createGraphQLServer = (config: ServerConfig): GraphQLServer => {
-  const plugins = config.cacheEnabled || DEFAULT_CACHE_ENABLED
+  const plugins = config.cacheEnabled
     ? [
       useResponseCache({
         // global cache per language, shared by all users
@@ -132,10 +168,8 @@ export const createGraphQLServer = (config: ServerConfig): GraphQLServer => {
             request.headers.get("accept-language") || DEFAULT_LANGUAGE,
           ),
         ttlPerSchemaCoordinate: {
-          "Query.projects": config.cacheTtlMsBetterplace ||
-            DEFAULT_CACHE_TTL_MS_BETTERPLACE,
-          "Query.project": config.cacheTtlMsBetterplace ||
-            DEFAULT_CACHE_TTL_MS_BETTERPLACE,
+          "Query.projects": config.cacheTtlMsBetterplace,
+          "Query.project": config.cacheTtlMsBetterplace,
         },
       }),
     ]
@@ -174,13 +208,18 @@ type GraphQLContext = {
 export const startServer = (config: ServerConfig): Promise<void> => {
   const graphQLServer: GraphQLServer = createGraphQLServer(config);
   return serve(graphQLServer.handleRequest, {
-    port: config.port || DEFAULT_PORT,
+    port: config.port,
     onListen({ port, hostname }) {
       logger.info(
         `Server started at http://${
           hostname === "0.0.0.0" ? "localhost" : hostname
         }:${port}/graphql`,
       );
+      if (config.fake) {
+        logger.info(
+          `Server is serving fake data due to FAKE env var set to true`,
+        );
+      }
     },
   });
 };