January 17, 2025
How to Build a Social Network in 1 Day: Part 2 – Laying the Foundation
Set up your social network app's foundation by cleaning the structure, integrating NativeWind, and handling safe area boundaries.

In Part 1, we set the stage for our journey into building a social network app, discussing what lies ahead and the tools we’ll use. Now it’s time to roll up our sleeves and get to work. In this chapter, we’ll focus on setting up the foundation for our project. By the end of this section, you’ll have an Expo repository ready to go, equipped with TypeScript and NativeWind (Tailwind CSS for React Native), and a clean structure prepared for our app’s screens.

Let’s dive in!

Part 1 completed repo on GitHub for reference

Step 1: Creating the Expo App

To begin, navigate to the directory where you want to create your repository. Open your terminal and run the following command:

npx create-expo-app@latest

Follow the prompts to configure your project. Once the setup is complete, navigate into the newly created repository:

cd <your-repo-name>

Open the project in your IDE of choice, such as Visual Studio Code.

Step 2: Cleaning Up the Project Structure

We want to start with a clean slate, so let’s tidy up the default files and folders created by Expo.

Remove Unnecessary Files

  • Components, Constants, and Hooks: Delete the contents of the components, constants, and hooks folders.
  • Scripts Folder: Delete the scripts folder located at the root of your project (which contains reset-project.js).

Clean Up Screens in the app Folder

  • Inside the app folder, remove screens you won’t be using.
  • For the remaining screens, clear out their contents, leaving placeholders or empty functional components as needed.

Final Folder Structure

After this cleanup, your project structure should look like this:

.gitignore
app  
  └─ (tabs)
    ├─ index.tsx
    └─ _layout.tsx
  └─ _layout.tsx
app.json
assets
  ├─ fonts
  │   └─ SpaceMono-Regular.ttf
  └─ images
      ├─ adaptive-icon.png
      ├─ icon.png
      └─ splash-icon.png
components
constants
hooks
package-lock.json
package.json
README.md
tsconfig.json

This streamlined setup ensures we stay focused and keep our project organized as we build out the app.

Cleaned Up Files

Here are the cleaned-up contents of the key files:

app/_layout.tsx

import { useFonts } from "expo-font";
import { Stack } from "expo-router";
import * as SplashScreen from "expo-splash-screen";
import { StatusBar } from "expo-status-bar";
import { useEffect } from "react";
import { View } from "react-native";
import "react-native-reanimated";

// Prevent the splash screen from auto-hiding before asset loading is complete.
SplashScreen.preventAutoHideAsync();

export default function RootLayout() {
  const [loaded] = useFonts({
    SpaceMono: require("../assets/fonts/SpaceMono-Regular.ttf"),
  });

  useEffect(() => {
    if (loaded) {
      SplashScreen.hideAsync();
    }
  }, [loaded]);

  if (!loaded) {
    return null;
  }

  return (
    <View>
      <Stack>
        <Stack.Screen name="(tabs)" options={{ headerShown: false }} />
      </Stack>
      <StatusBar style="auto" />
    </View>
  );
}

app/(tabs)/_layout.tsx

import { Tabs } from "expo-router";
import React from "react";

export default function TabLayout() {
  return (
    <Tabs
      screenOptions={{
        headerShown: false,
      }}
    >
      <Tabs.Screen name="index" />
    </Tabs>
  );
}

app/(tabs)/index.tsx

import { View } from "react-native";

export default function HomeScreen() {
  return <View></View>;
}

This streamlined setup ensures we stay focused and keep our project organized as we build out the app.

Step 3: Setting Up NativeWind

NativeWind is a library that brings the simplicity and power of Tailwind CSS to React Native. Tailwind CSS is a utility-first CSS framework that allows you to rapidly build modern and responsive designs by applying pre-defined utility classes directly to your components. NativeWind adapts this for React Native, enabling you to style your app with ease and consistency.

Configuration Steps

  • Follow the NativeWind Setup Guide: Use the NativeWind setup guide and select the Expo setup. Make sure to follow the latest version, as this tutorial is based on Expo SDK 52 at the time of writing.
  • Update the Tailwind Config File: Ensure your tailwind.config.js includes the components folder in addition to the app folder
/** @type {import('tailwindcss').Config} */
module.exports = {
  // NOTE: Update this to include the paths to all of your component files.
  content: ["./app/**/*.{js,jsx,ts,tsx}", "./components/**/*.{js,jsx,ts,tsx}"],
  presets: [require("nativewind/preset")],
  theme: {
    extend: {},
  },
  plugins: [],
};
  • Create and Import the globals.css File: At the root of your project (same level as package.json), create a file named globals.css. Copy the content from the NativeWind guide into this file. Then, import it at the top of app/_layout.tsx:
import "../globals.css";
  • Generate and Edit babel.config.js: If your project doesn’t include a babel.config.js file (as Expo hides it by default), generate one by running:
npx expo customize
  • Select the babel.config.js option using the space bar and hit Enter. Once generated, copy the content from the NativeWind guide into this file.
  • Generate and Edit metro.config.js: Similarly, if your project lacks a metro.config.js file, generate it using the same steps. Copy the content from the NativeWind guide into this file as well.
  • Edit app.json: The NativeWind guide includes instructions for modifying the web section in the app.json file. However, since we are building for mobile only, you can safely remove the entire web section. Your app.json file should now look like this, with the rest of its content untouched:
{
  "expo": {
    // other configurations here
  }
}
  • TypeScript Configuration (Required): Create a file named nativewind-env.d.ts at the root of your project with the following content (This step is required for proper type support in our TypeScript-based app):
/// <reference types="nativewind/types" />

Verification

Before running your app, ensure you’ve updated the screen files to the following:

app/_layout.tsx

<View className="flex-1">
  <Stack>
    <Stack.Screen name="(tabs)" options={{ headerShown: false }} />
  </Stack>
  <StatusBar style="auto" />
</View


app/(tabs)/index.tsx

<View className="bg-red-500 flex-1">
  <Text>Hello World</Text>
</View>


Once these steps are complete, start your app with the following command:

npx expo start

You should now see an ugly red screen with a Hello World text in the top left corner (it will be behind the status bar as it’s outside the safe area), and a tab navigation bar at the bottom with a single tab. At this point, we’re almost done!

Step 4: Setting Up SafeAreaProvider and SafeAreaView

Lastly, we will incorporate the SafeAreaProvider and SafeAreaView components into our app, which are part of the react-native-safe-area-context library. These components help ensure that your content is displayed within the safe area boundaries of a device, avoiding overlaps with the status bar, notch, or other UI elements.

  • SafeAreaProvider: This component provides the context for safe area boundaries and should wrap your entire application.
  • SafeAreaView: This component applies the safe area insets to its children. It can be used selectively for specific screens or layouts where you want to ensure the content is contained within the safe area.

For simplicity, in this tutorial, we’ll wrap the entire app with SafeAreaView. Here's how to integrate it:

  • Import SafeAreaProvider and SafeAreaView into app/_layout.tsx:
import { SafeAreaProvider, SafeAreaView } from "react-native-safe-area-context";
  • Update the app/_layout.tsx file to wrap your app as follows:
<SafeAreaProvider>
      <SafeAreaView className="flex-1">
        <Stack>
          <Stack.Screen name="(tabs)" options={{ headerShown: false }} />
        </Stack>
      </SafeAreaView>
      <StatusBar style="auto" />
</SafeAreaProvider>

By wrapping the app with SafeAreaProvider and SafeAreaView, we ensure all screens respect the safe area. While it’s possible to use SafeAreaView selectively for specific screens, we are keeping it simple by applying it globally in this tutorial.

Once you’ve made these updates, update your app or simply re-run it using:

npx expo start

You should now see the red screen with a Hello World message, properly contained within the safe area and a tab navigation bar at the bottom.

Wrapping Up

With this setup complete, your app is now ready to be built! We’ve laid the foundation by setting up the project structure, integrating NativeWind, and ensuring our app respects the device’s safe area boundaries.

In the next part of this tutorial, we’ll focus on authenticating users. Stay tuned, as this is where your social network starts coming to life!

Stay Updated

Don’t forget to join the Discord server where I post free boilerplate code repos for different types of social networks. Updates about the next article and additional resources will also be shared there. Lastly, follow me for updates here and on X/Twitter & BlueSky.