INVU

How to Create a Dynamic Blog on Neocities

Dynamic blog on a static site? It's easier than you think.

One of the biggest limitations of static hosts like Neocities is that there's no database and no server-side code.

At first glance, that seems like it rules out things like:

blogs
linklogs
status updates
changelogs
bookmarks

But here's the trick: Let GitHub host your data and let JavaScript load it. Using a GitHub Gist as a tiny database, you can update your content from anywhere and have your Neocities site automatically display the latest version. No PHP. No Node. No backend. Just HTML, JavaScript, JSON, and a little ingenuity. What we're building

We'll create:

 /links/
   |--- index.html
   |--- add.html

And we'll store our post data in a GitHub Gist:

JSON
[
{
"title": "Neocities",
"url": "https://neocities.org",
"description": "Free static site web hosting with no ads.",
"date": "2026-08-27"
}
]

Whenever the Gist is updated, the site updates automatically.

Step 1: Create a GitHub Gist

Go to: https://gist.github.com . Create a new public Gist.
Name the file: links.json.
Add some sample data:

JSON

[
  {
    "title": "Neocities",
    "url": "https://neocities.org",
    "description": "Free static site web hosting with no ads.",
    "date": "2026-08-27"
  }
]
Save it.

Step 2: Get Your Gist ID

Your Gist URL will look something like:
https://gist.github.com/username/d8cd18b09cfaf82f61e4e647798156c1
Copy the long ID: d8cd18b09cfaf82f61e4e647798156c1.

Step 3: Create index.html

Create a place for the links to appear:

        
    
Then add JavaScript:


How to Create a Dynamic Blog on Neocities

Dynamic blog on a static site? It's easier than you think.

One of the biggest limitations of static hosts like Neocities is that there's no database and no server-side code.

At first glance, that seems like it rules out things like blogs, linklogs, status updates, changelogs, and bookmarks.

But here's the trick:

Let GitHub host your data and let JavaScript load it.

Using a GitHub Gist as a tiny database, you can update your content from anywhere and have your Neocities site automatically display the latest version.

No PHP. No Node. No backend.

Just HTML, JavaScript, JSON, and a little ingenuity.


What We're Building

/links/
├── index.html
└── add.html

We'll store our content in a GitHub Gist:

[
  {
    "title": "Neocities",
    "url": "https://neocities.org",
    "description": "Free static site web hosting with no ads.",
    "date": "2026-08-27"
  }
]

Whenever the Gist is updated, the site updates automatically.


Step 1: Create a GitHub Gist

Visit:

https://gist.github.com

Create a new public Gist and name the file:

links.json

Add some sample data:

[
  {
    "title": "Neocities",
    "url": "https://neocities.org",
    "description": "Free static site web hosting with no ads.",
    "date": "2026-08-27"
  }
]

Step 2: Get Your Gist ID

Your Gist URL will look something like:

https://gist.github.com/username/d8cd18b09cfaf82f61e4e647798156c1

Copy the long ID:

d8cd18b09cfaf82f61e4e647798156c1

Step 3: Create index.html

Create a container for your links:

<div id="links"></div>

Then add JavaScript to pull the latest version of your Gist through GitHub's API:

<script>

const GIST_ID =
  "d8cd18b09cfaf82f61e4e647798156c1";

async function loadLinks() {

  const gist = await fetch(
    `https://api.github.com/gists/${GIST_ID}`
  ).then(r => r.json());

  const rawUrl =
    gist.files["links.json"].raw_url;

  const links =
    await fetch(rawUrl).then(r => r.json());

  const container =
    document.getElementById("links");

  container.innerHTML = "";

  links.slice().reverse().forEach(link => {

    const el = document.createElement("article");

    el.innerHTML = `
      <h2>
        <a href="${link.url}">
          ${link.title}
        </a>
      </h2>

      <small>${link.date}</small>

      <p>${link.description}</p>
    `;

    container.appendChild(el);

  });

}

loadLinks();

</script>

The cool part: GitHub automatically gives us the newest raw URL every time we load the page, so we never have to update links manually.


Step 4: Create add.html

Let's build a helper page to generate new entries.

<input id="title">
<input id="url">
<textarea id="description"></textarea>

<button onclick="generate()">
Generate JSON
</button>

<pre id="output"></pre>

Now add:

<script>

function generate() {

  const title =
    document.getElementById("title").value;

  const url =
    document.getElementById("url").value;

  const description =
    document.getElementById("description").value;

  const date =
    new Date().toISOString().slice(0,10);

  const json =
    JSON.stringify({
      title,
      url,
      description,
      date
    }, null, 2) + ",";

  document
    .getElementById("output")
    .textContent = json;

  navigator.clipboard.writeText(json);

}

</script>

Now you can:

  1. Enter a link.
  2. Click Generate.
  3. The JSON is copied to your clipboard.
  4. Paste it into your Gist.
  5. Save.

Step 5: Add a Shortcut to Your Gist

Create a big obvious button:

<a href="https://gist.github.com/username/YOUR_GIST_ID/edit"
   target="_blank">
   Open Gist Editor
</a>

Your publishing workflow now looks like:

Visit add.html
        ↓
Generate JSON
        ↓
Copy
        ↓
Open Gist Editor
        ↓
Paste
        ↓
Save

Why This Works

Neocities remains completely static.

GitHub stores your content.

JavaScript stitches them together in the browser.

The result feels like a dynamic blog even though there is no database and no server-side code anywhere.

This same pattern works for:

  • Blogs
  • Linklogs
  • Bookmarks
  • Status updates
  • Reading journals
  • Project logs
  • Changelogs

Bonus: Embed It Anywhere

You don't even have to make it a standalone page.

If your linklog lives at:

/links/index.html

You can embed it elsewhere with an iframe:

<iframe
  src="/links/index.html"
  width="100%"
  height="800">
</iframe>

This lets you maintain a single source of content while displaying it across multiple pages on your site.


Conclusion

Congratulations. You've just built a lightweight CMS using nothing but Neocities, GitHub Gist, JSON, and a little client-side JavaScript.

No backend. No database. No framework.

Just static files, clever hacks, and the open web.

Pretty neato burrito. 🌯



Making It Look Like a Real Blog

At this point you have a working dynamic blog, but it probably looks like a plain list of links. Let's fix that.

One of the nice things about this setup is that your content and presentation are completely separate. You can redesign the site whenever you want without touching your JSON data.

Here's a simple blog-style layout:

body {
    margin: 0;
    padding: 30px;

    background:
        linear-gradient(
            to bottom,
            #f0f0f0,
            #d8d8d8
        );

    color: #222;

    font-family:
        Verdana,
        Arial,
        sans-serif;

    line-height: 1.5;
}

#page {
    max-width: 860px;
    margin: 0 auto;
}

article {
    background: white;

    border: 1px solid #bbb;
    border-top: 4px solid #3388ff;

    padding: 18px;

    margin-bottom: 20px;

    box-shadow:
        0 2px 8px rgba(0,0,0,.15);
}

article h2 {
    margin: 0 0 6px 0;
}

article h2 a {
    color: #3388ff;
    text-decoration: none;
}

article h2 a:hover {
    color: #ff0066;
    text-decoration: underline;
}

small {
    color: #8833ee;
    font-weight: bold;
}

.url {
    font-size: 11px;
    color: #666;
}

This creates the classic early-2000s web magazine look:

  • Boxed articles
  • Colored borders
  • Subtle drop shadows
  • Blue headlines
  • Strong datelines

Building a Masthead

A good blog deserves a proper logo.

Instead of a plain heading, try something like this:

<h1>
    Links
    <span class="tagline">
        from the underground
    </span>
</h1>

Then style the tagline to look like a piece of fluorescent tape stuck onto your logo:

.tagline {
    display: inline-block;

    margin-left: 16px;

    padding: 6px 16px;

    background:
        linear-gradient(
            to bottom,
            #fffd77,
            #fff040
        );

    color: #111;

    font-family:
        "Trebuchet MS",
        sans-serif;

    font-size: 11px;
    font-weight: bold;

    text-transform: uppercase;
    letter-spacing: 2px;

    transform: rotate(-4deg);

    box-shadow:
        0 2px 0 rgba(0,0,0,.3),
        3px 4px 8px rgba(0,0,0,.25);
}

Now it looks less like a webpage and more like somebody slapped a piece of painter's tape onto a glossy magazine logo with a Sharpie.


Add a Dateline

You can automatically display today's date:

<div class="edition">
    <span class="edition-label">
        EDITION
    </span>

    <span id="dateline"></span>

    <span class="edition-sep">
        •
    </span>

    <span class="edition-note">
        crafted by human hands • updated frequently
    </span>
</div>

And the JavaScript:

function updateDateline() {

    const now = new Date();

    document.getElementById("dateline")
        .textContent =
        now.toLocaleDateString(
            "en-US",
            {
                month: "long",
                day: "numeric",
                year: "numeric"
            }
        );

}

updateDateline();

The result looks something like:

EDITION August 29, 2026 • crafted by human hands • updated frequently

Little touches like this help transform a simple JSON feed into something that feels like a real publication.