/how-to-build-replit

How to Build a Social media feed with Replit

Learn how to build a social media feed using Replit. Follow easy steps to code, connect APIs, and create a dynamic, shareable social platform.

Matt Graham, CEO of Rapid Developers

Book a call with an Expert

Starting a new venture? Need to upgrade your web app? RapidDev builds application with your growth in mind.

How to Build a Social media feed with Replit

A simple and realistic way to build a social media feed on Replit is to create a small full‑stack app using Node.js (Express) for the backend and HTML, CSS, JavaScript for the frontend. You’ll store posts in a small JSON file or a hosted database like Replit’s Database. The backend will expose routes for posting and fetching posts, and the frontend will call those routes with fetch() to display the feed. This setup works entirely inside one Replit project, can be collaboratively edited, and deployed using Replit’s built‑in web server environment.

 

Step 1: Set up your project structure

 

In Replit, create a new Repl using the “Node.js” template. Your folder structure will look like this:

  • index.js – main server file (backend)
  • public/ – folder for static frontend files
  • public/index.html – main feed page
  • public/script.js – client logic
  • public/style.css – styling
  • posts.json – small local data store (or use Replit DB as optional alternative)

 

Step 2: Install dependencies

 

npm install express body-parser

 

Step 3: Write backend in index.js

 

// index.js
const express = require("express")
const fs = require("fs")
const bodyParser = require("body-parser")
const app = express()
const PORT = 3000

// Middleware to parse JSON
app.use(bodyParser.json())
// Serve static files from public folder
app.use(express.static("public"))

// Helper to read and write posts from posts.json
function getPosts() {
  try {
    return JSON.parse(fs.readFileSync("posts.json", "utf8"))
  } catch {
    return []
  }
}
function savePosts(posts) {
  fs.writeFileSync("posts.json", JSON.stringify(posts, null, 2))
}

// Route to get all posts
app.get("/api/posts", (req, res) => {
  const posts = getPosts()
  res.json(posts)
})

// Route to add new post
app.post("/api/posts", (req, res) => {
  const posts = getPosts()
  const newPost = {
    id: Date.now(),
    text: req.body.text || "",
    createdAt: new Date().toISOString()
  }
  posts.unshift(newPost) // add to top of feed
  savePosts(posts)
  res.json(newPost)
})

app.listen(PORT, () => console.log(`Server running on port ${PORT}`))

✅ Save this file in the root of your project. This will be your main web server file in Replit, which automatically runs when you press the “Run” button.

 

Step 4: Create public/index.html

 

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
    <title>Mini Social Feed</title>
    <link rel="stylesheet" href="style.css" />
  </head>
  <body>
    <h1>My Social Feed</h1>
    <form id="postForm">
      <input id="postText" type="text" placeholder="What's on your mind?" required />
      <button type="submit">Post</button>
    </form>
    <div id="feed"></div>
    <script src="script.js"></script>
  </body>
</html>

This page has a simple form for submitting posts and a container (feed) for showing them.

 

Step 5: Create public/script.js

 

// public/script.js

async function loadFeed() {
  const response = await fetch("/api/posts")
  const posts = await response.json()
  const feedDiv = document.getElementById("feed")

  feedDiv.innerHTML = "" // clear old content
  posts.forEach(post => {
    const div = document.createElement("div")
    div.className = "post"
    div.innerHTML = `<p>${post.text}</p><small>${new Date(post.createdAt).toLocaleString()}</small>`
    feedDiv.appendChild(div)
  })
}

document.getElementById("postForm").addEventListener("submit", async (e) => {
  e.preventDefault()
  const textInput = document.getElementById("postText")
  const newPost = { text: textInput.value }
  await fetch("/api/posts", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify(newPost)
  })
  textInput.value = ""
  loadFeed() // refresh after posting
})

// Load feed on page load
loadFeed()

This script uses the browser’s fetch API to call your server’s endpoints. When the user submits a new post, it’s stored on the backend and instantly refreshed on screen.

 

Step 6: Create simple public/style.css

 

body {
  font-family: Arial, sans-serif;
  max-width: 600px;
  margin: 2em auto;
  background: #f4f4f4;
  padding: 1em;
}

.post {
  background: white;
  padding: 1em;
  margin-bottom: 1em;
  border-radius: 5px;
  box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}

 

Step 7: Add posts.json in root

 

[]

This starts as an empty array; the server will fill it up with your posts.

 

Step 8: Run and Test

 

Click “Run” in Replit. The console should show “Server running on port 3000.” Then open the preview (or click the webview icon). Type a message and post — you’ll see your feed update instantly. The data persists as long as your Repl is alive.

 

Step 9: Optional – use Replit Database instead of posts.json

 

// If you prefer Replit Database:
// 1. Install: npm install @replit/database
const Database = require("@replit/database")
const db = new Database()

// Replace getPosts and savePosts:
async function getPosts() {
  return (await db.get("posts")) || []
}
async function savePosts(posts) {
  await db.set("posts", posts)
}

This way the data stays even when the container resets, and no manual file writes are needed.

 

Useful Tips

 

  • Always use express.static to serve frontend files; Replit automatically maps your Repl’s web view to the server’s port.
  • Use Autosave carefully: if file writes in posts.json happen too often, cache them or use the built‑in database.
  • Store keys or future user tokens in the “Secrets” tab, never in your code.
  • For real authentication, later integrate something like Firebase Auth or simple username & password hashed logic, but start small first.

 

That’s a complete and working social feed foundation inside Replit: one Express backend, one static frontend, data persistence via JSON or Replit DB, and instant live preview.

Want to explore opportunities to work with us?

Connect with our team to unlock the full potential of no-code solutions with a no-commitment consultation!

Contact Us

How to create and manage a simple social media feed backend with Express and Replit Database


<!-- server.js -->
<script type="module">
import express from "express";
import { Database } from "@replit/database";

const db = new Database();
const app = express();
app.use(express.json());

// Structure posts in a feed collection
// Each post: { id, author, content, createdAt, likes }
app.post("/api/posts", async (req, res) => {
  const { author, content } = req.body;
  if (!author || !content) return res.status(400).json({ error: "Missing fields" });

  const id = Date.now().toString();
  const post = { id, author, content, createdAt: new Date().toISOString(), likes: 0 };

  await db.set(id, post);
  res.status(201).json(post);
});

// Pagination + ordering newest first
app.get("/api/feed", async (req, res) => {
  const allPosts = await db.list();
  const posts = await Promise.all(allPosts.map(async key => await db.get(key)));
  posts.sort((a, b) => new Date(b.createdAt) - new Date(a.createdAt));

  const page = parseInt(req.query.page || "1");
  const limit = 5;
  const start = (page - 1) \* limit;
  const end = start + limit;
  res.json({ page, posts: posts.slice(start, end) });
});

app.post("/api/posts/:id/like", async (req, res) => {
  const post = await db.get(req.params.id);
  if (!post) return res.status(404).json({ error: "Not found" });
  post.likes += 1;
  await db.set(req.params.id, post);
  res.json(post);
});

app.listen(3000, () => console.log("Server running on port 3000"));
</script>

How to Fetch User Avatars and Create Feed Posts in Replit


<!-- server.js -->
<script type="module">
import express from "express";
import fetch from "node-fetch";
import { config } from "dotenv";

config();
const app = express();
app.use(express.json());

// Example: fetching user profile pictures from an external avatar API (e.g., DiceBear)
app.get("/api/users/:username/avatar", async (req, res) => {
  const { username } = req.params;
  try {
    const response = await fetch(`https://api.dicebear.com/7.x/thumbs/svg?seed=${encodeURIComponent(username)}`);
    if (!response.ok) throw new Error("Avatar service failed");
    const svg = await response.text();
    res.setHeader("Content-Type", "image/svg+xml");
    res.send(svg);
  } catch (err) {
    res.status(500).json({ error: "Failed to fetch avatar" });
  }
});

// Example: posting a new feed item that auto-includes an external avatar and summary
app.post("/api/feed", async (req, res) => {
  const { username, text } = req.body;
  if (!username || !text) return res.status(400).json({ error: "Missing fields" });

  try {
    const avatarResponse = await fetch(`https://api.dicebear.com/7.x/thumbs/svg?seed=${encodeURIComponent(username)}`);
    const avatarSvg = await avatarResponse.text();
    const post = {
      id: Date.now().toString(),
      author: username,
      content: text,
      avatar: `data:image/svg+xml;base64,${Buffer.from(avatarSvg).toString("base64")}`,
      createdAt: new Date().toISOString(),
    };

    // For real usage, save post in @replit/database, MongoDB Atlas, etc.
    res.status(201).json(post);
  } catch (err) {
    res.status(500).json({ error: "Failed to create post" });
  }
});

app.listen(3000, () => console.log("Server running on port 3000"));
</script>

How to Build a Feed API for Your Social Media App on Replit


<!-- server.js -->
<script type="module">
import express from "express";
import { Database } from "@replit/database";

const app = express();
const db = new Database();

app.use(express.json());

// Route to fetch feed items with optimistic UI-friendly timestamps and caching
app.get("/api/feed", async (req, res) => {
  try {
    const cursor = req.query.after ? parseInt(req.query.after) : Date.now();
    const allKeys = await db.list();
    const posts = await Promise.all(allKeys.map(k => db.get(k)));

    const sorted = posts
      .filter(p => !!p)
      .sort((a, b) => new Date(b.createdAt) - new Date(a.createdAt))
      .filter(p => new Date(p.createdAt).getTime() < cursor)
      .slice(0, 5);

    const nextCursor = sorted.length ? new Date(sorted[sorted.length - 1].createdAt).getTime() : null;

    res.json({
      posts: sorted,
      nextCursor,
      fetchedAt: new Date().toISOString()
    });
  } catch {
    res.status(500).json({ error: "Feed fetch failed" });
  }
});

// New post that triggers cache invalidation key in db for front-end ETag
app.post("/api/posts", async (req, res) => {
  const { author, content } = req.body;
  if (!author || !content) return res.status(400).json({ error: "Missing fields" });

  const id = Date.now().toString();
  const post = { id, author, content, createdAt: new Date().toISOString(), likes: 0 };
  await db.set(id, post);

  const cacheToken = Math.random().toString(36).slice(2);
  await db.set("feed_cache_token", cacheToken);

  res.status(201).json({ post, cacheToken });
});

app.get("/api/feed/cache-token", async (req, res) => {
  const token = await db.get("feed_cache_token");
  res.json({ token });
});

app.listen(3000, () => console.log("Feed service running on port 3000"));
</script>

Want to explore opportunities to work with us?

Connect with our team to unlock the full potential of no-code solutions with a no-commitment consultation!

Contact Us
Matt Graham, CEO of Rapid Developers

Book a call with an Expert

Starting a new venture? Need to upgrade your web app? RapidDev builds application with your growth in mind.

Best Practices for Building a Social media feed with Replit

Building a social media feed on Replit works best if you separate your logic clearly: a backend API (Node.js with Express) that handles posts, users, and storage (for example, MongoDB Atlas), and a frontend (React or basic HTML/JS) that fetches and displays that data. You must rely on environment variables for secrets (like MongoDB credentials), use Replit’s built-in web server to serve your API, and keep files structured so you don’t break Replit’s automatic runner. Replit can easily host small-to-medium feeds if you manage data well and avoid long-running background jobs.

 

Project Structure

 

Create a Node.js Repl and organize it like this:

/ (root)
 ├── index.js          // Your entry file - Replit runs this automatically
 ├── routes/
 │    └── posts.js     // All endpoints for creating/fetching posts
 ├── models/
 │    └── Post.js      // Mongoose (MongoDB) schema
 ├── public/
 │    └── index.html   // Simple feed display
 ├── .replit           // Replit configuration file
 └── package.json

 

Setup MongoDB Integration

 

Use MongoDB Atlas—it’s compatible with Replit and free for small projects. In Replit:

  • Open the Secrets tab (lock icon in left sidebar).
  • Add a key named MONGO\_URI and paste your connection string as value.

 

Backend: Server (index.js)

 

This file starts your Express server, connects to MongoDB, and includes your routes.

import express from "express"
import mongoose from "mongoose"
import postsRouter from "./routes/posts.js"

const app = express()

// Middleware to parse JSON request bodies
app.use(express.json()) 

// Connect to MongoDB using secret from Replit
mongoose.connect(process.env.MONGO_URI, {
  useNewUrlParser: true,
  useUnifiedTopology: true
}).then(() => console.log("Connected to MongoDB"))
.catch(err => console.error(err))

// Include routes
app.use("/api/posts", postsRouter)

// Serve static frontend from /public
app.use(express.static("public"))

// Start server
app.listen(3000, () => console.log("Server running on port 3000"))

 

Post Model (models/Post.js)

 

import mongoose from "mongoose"

const postSchema = new mongoose.Schema({
  author: String,
  content: String,
  createdAt: { type: Date, default: Date.now }
})

export default mongoose.model("Post", postSchema)

 

Routes (routes/posts.js)

 

This creates two endpoints – one to list posts, another to add a new post.

import express from "express"
import Post from "../models/Post.js"

const router = express.Router()

// Get all posts
router.get("/", async (req, res) => {
  const posts = await Post.find().sort({ createdAt: -1 })
  res.json(posts)
})

// Add a post
router.post("/", async (req, res) => {
  const { author, content } = req.body
  const newPost = new Post({ author, content })
  await newPost.save()
  res.json(newPost)
})

export default router

 

Frontend (public/index.html)

 

This is a simple HTML/JS feed that interacts with your API.

<!DOCTYPE html>
<html>
  <head>
    <title>My Social Feed</title>
    <style>
      body { font-family: Arial; margin: 20px; }
      .post { margin-bottom: 15px; padding: 10px; border: 1px solid #ddd; }
    </style>
  </head>
  <body>
    <h2>My Social Feed</h2>
    <form id="post-form">
      <input id="author" placeholder="Your name" required />
      <textarea id="content" placeholder="Write something..." required></textarea>
      <button type="submit">Post</button>
    </form>
    <div id="feed"></div>

    <script>
      async function loadPosts() {
        const res = await fetch("/api/posts")
        const posts = await res.json()
        const feed = document.getElementById("feed")
        feed.innerHTML = ""
        posts.forEach(p => {
          const div = document.createElement("div")
          div.className = "post"
          div.textContent = `${p.author}: ${p.content}`
          feed.appendChild(div)
        })
      }

      document.getElementById("post-form").addEventListener("submit", async (e) => {
        e.preventDefault()
        const author = document.getElementById("author").value
        const content = document.getElementById("content").value
        await fetch("/api/posts", {
          method: "POST",
          headers: {"Content-Type": "application/json"},
          body: JSON.stringify({ author, content })
        })
        e.target.reset()
        loadPosts()
      })

      loadPosts()
    </script>
  </body>
</html>

 

Practical Replit Tips

 

  • Use Secrets properly: Never put your MongoDB URI directly in code. Replit exposes env vars with process.env.<NAME>.
  • Keep Express lightweight: Replit sleeps inactive Repls, so persist data in MongoDB, not in memory.
  • Use the “Run” button responsibly: Point it to npm start or node index.js in the .replit file. Example: run = "npm start".
  • Version-control through the Git button; avoid large uploads and image hosting inside Replit — use external services (Cloudinary, Supabase storage, etc.).
  • Multiplayer debugging: Replit’s built-in multiplayer helps teammates debug in real-time — ideal for quick fixes or schema adjustments.

 

Result

 

After running your Repl, you’ll have a functioning social feed: posts are stored in MongoDB, retrieved dynamically, and the frontend updates instantly after each post. For larger scale or authentication features, you can expand with JWT or Replit Auth, but this structure is the clean, safe, and “Replit-friendly” foundation for your social feed.

Client trust and success are our top priorities

When it comes to serving you, we sweat the little things. That’s why our work makes a big impact.

Rapid Dev was an exceptional project management organization and the best development collaborators I've had the pleasure of working with. They do complex work on extremely fast timelines and effectively manage the testing and pre-launch process to deliver the best possible product. I'm extremely impressed with their execution ability.

CPO, Praction - Arkady Sokolov

May 2, 2023

Working with Matt was comparable to having another co-founder on the team, but without the commitment or cost. He has a strategic mindset and willing to change the scope of the project in real time based on the needs of the client. A true strategic thought partner!

Co-Founder, Arc - Donald Muir

Dec 27, 2022

Rapid Dev are 10/10, excellent communicators - the best I've ever encountered in the tech dev space. They always go the extra mile, they genuinely care, they respond quickly, they're flexible, adaptable and their enthusiasm is amazing.

Co-CEO, Grantify - Mat Westergreen-Thorne

Oct 15, 2022

Rapid Dev is an excellent developer for no-code and low-code solutions.
We’ve had great success since launching the platform in November 2023. In a few months, we’ve gained over 1,000 new active users. We’ve also secured several dozen bookings on the platform and seen about 70% new user month-over-month growth since the launch.

Co-Founder, Church Real Estate Marketplace - Emmanuel Brown

May 1, 2024 

Matt’s dedication to executing our vision and his commitment to the project deadline were impressive. 
This was such a specific project, and Matt really delivered. We worked with a really fast turnaround, and he always delivered. The site was a perfect prop for us!

Production Manager, Media Production Company - Samantha Fekete

Sep 23, 2022