{"id":15290445,"url":"https://github.com/stackbit/sourcebit-target-next","last_synced_at":"2025-10-13T17:14:04.009Z","repository":{"id":38384532,"uuid":"246630624","full_name":"stackbit/sourcebit-target-next","owner":"stackbit","description":"A Sourcebit target plugin for Next.js","archived":false,"fork":false,"pushed_at":"2023-05-03T21:58:19.000Z","size":276,"stargazers_count":4,"open_issues_count":7,"forks_count":3,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-08-21T08:37:35.029Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/stackbit.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2020-03-11T17:01:00.000Z","updated_at":"2025-02-11T14:05:10.000Z","dependencies_parsed_at":"2025-04-13T10:11:29.075Z","dependency_job_id":"2842219a-5ad5-4a52-a6dc-b297076f7efd","html_url":"https://github.com/stackbit/sourcebit-target-next","commit_stats":null,"previous_names":["stackbithq/sourcebit-target-next"],"tags_count":19,"template":false,"template_full_name":null,"purl":"pkg:github/stackbit/sourcebit-target-next","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stackbit%2Fsourcebit-target-next","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stackbit%2Fsourcebit-target-next/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stackbit%2Fsourcebit-target-next/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stackbit%2Fsourcebit-target-next/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/stackbit","download_url":"https://codeload.github.com/stackbit/sourcebit-target-next/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stackbit%2Fsourcebit-target-next/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":279016287,"owners_count":26085827,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-13T02:00:06.723Z","response_time":61,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-09-30T16:08:12.804Z","updated_at":"2025-10-13T17:14:03.993Z","avatar_url":"https://github.com/stackbit.png","language":"JavaScript","readme":"# sourcebit-target-next\n\n[![npm version](https://badge.fury.io/js/sourcebit-target-next.svg)](https://badge.fury.io/js/sourcebit-target-next)\n\n\u003e A [Sourcebit](https://github.com/stackbithq/sourcebit) target plugin for the [Next.js](https://nextjs.org/) framework.\n\n## Overview\n\nThis plugin allows consuming content loaded by any of the Sourcebit source plugins (e.g., [sourcebit-source-filesystem], \n[sourcebit-source-contentful] , [sourcebit-source-sanity]) inside Next.js pages using [getStaticProps] and [getStaticPaths]\nmethods.\n\n1. When Next.js starts, it loads Sourcebit and runs its `fetch()` method that executes Sourcebit plugins.\n2. A Sourcebit source plugin loads the content from a CMS or a file-system.\n3. The `sourcebit-target-next` plugin caches the loaded content and saves it inside the `.sourcebit-nextjs-cache.json` file.\n4. When Next.js renders a page, it calls [getStaticProps] and [getStaticPaths] methods. These methods call\n   the `sourcebitDataClient.getData()` method to load the content cached inside the `.sourcebit-nextjs-cache.json` file and\n   reduce it according to the needs of a particular page. \n\n![sourcebit-target-next diagram](docs/sourcebit-target-next.png)\n\n## Installation\n\n1. Install the main `sourcebit` package, this `sourcebit-target-next` plugin, and one of the Sourcebit \"source\" plugins to fetch your content (e.g., [sourcebit-source-filesystem],\n   [sourcebit-source-contentful], [sourcebit-source-sanity], or create your own).\n\n    ```\n    npm install sourcebit sourcebit-target-next sourcebit-source-filesystem\n    ```\n\n2. Create `sourcebit.js` configuration file in the root of your Next.js project:\n\n   ```javascript\n   const path = require('path');\n   const isDev = process.env.NODE_ENV === 'development';\n   \n   module.exports = {\n       plugins: [\n           /**\n            * The `sourcebit-source-filesystem` plugin reads content files from the provided `options.sources` folders,\n            * and generates an array of objects that is passed to the subsequent plugins.\n            */\n           {\n               module: require('sourcebit-source-filesystem'),\n               options: {\n                   watch: isDev,\n                   sources: [\n                       { name: 'pages', path: path.join(__dirname, 'content/pages') },\n                       { name: 'data', path: path.join(__dirname, 'content/data') }\n                   ]\n               }\n           },\n   \n           /**\n            * If needed, add more plugins to transform the data\n            */\n           ({ data }) =\u003e {\n               return {\n                   ...data,\n                   objects: data.objects.map((object) =\u003e {\n                       // ... trasnform the objects\n                       return object;\n                   })\n               };\n           },\n   \n           /**\n            * The `sourcebit-target-next` plugin receives the data generated by `sourcebit-source-filesystem` plugin,\n            * and stores it in `.sourcebit-nextjs-cache.json` file.\n            */\n           {\n               module: require('sourcebit-target-next'),\n               options: {\n                   liveUpdate: isDev,\n                   flattenAssetUrls: true\n               }\n           }\n       ]\n   };\n   ```\n\n3. Wrap the config exported in `next.config.js` in the following way:\n\n    ```js\n    const withSourcebit = require('sourcebit').sourcebitNext();\n    \n    module.exports = withSourcebit({\n        // ... next.js config ...\n    });\n    ```\n   \n    The `withSourcebit` function loads the `sourcebit.js` config file and runs `sourcebit.fetch(config)` method for you,\n    before starting the Next.js server. If you want to control the process yourself, you can load the sourcebit config and call\n    `fetch()` manually:\n\n    ```js\n    const sourcebit = require('sourcebit');\n    const sourcebitConfig = require('./sourcebit.js');\n    sourcebit.fetch(sourcebitConfig);\n    ```\n\n4. To consume data fetched by Sourcebit and cached by `sourcebit-target-next`, import the `sourcebitDataClient` from\n   `sourcebit-target-next` and call its `getData()` method inside `getStaticPaths` and `getStaticProps` methods. You\n   can use one of the `__metadata` properties added by `sourcebit-source-filesystem` to generate props needed for a\n   particular page.\n\n   - If a page does not use [dynamic routes], then it should call the `getData()` method from `getStaticProps` to load\n     the cached data and compute the props specific to that page:\n\n     ```javascript\n     // src/pages/about.js\n   \n     import { sourcebitDataClient } from 'sourcebit-target-next';\n\n     export async function getStaticProps() {\n         const data = await sourcebitDataClient.getData();\n         const props = data.objects.find((object) =\u003e object?.__metadata?.relSourcePath === 'about.md')\n         return { props };\n     }\n     ```\n\n   - If a page does use [dynamic routes], e.g., `src/pages/[[...slug]].js`, then it should have both the `getStaticPaths`\n     and the `getStaticProps` methods. Use `getData()` in `getStaticPaths` to generate paths for all your pages, and\n     then in `getStaticProps` to compute props for a particular page according to the slug parameter.\n     \n     ```javascript\n     // src/pages/[[...slug]].js\n     \n     import { sourcebitDataClient } from 'sourcebit-target-next';\n\n     export async function getStaticPaths() {\n         const data = await sourcebitDataClient.getData();\n         const paths = data.objects\n             // find objects loaded from the \"pages\" folder (__metadata.sourceName === \"pages\")\n             .filter((object) =\u003e object?.__metadata?.sourceName === 'pages')\n             // map the file path to the page url, e.g.: 'about.md' =\u003e '/about'\n             .map((object) =\u003e urlPathFromFilePath(object?.__metadata?.relSourcePath))\n         return { paths };\n     }\n     \n     export async function getStaticProps() {\n         const urlPath = '/' + (params?.slug || []).join('/');\n         const data = await sourcebitDataClient.getData();\n         // find the objects corresponding to the requested page\n         const props = data.objects.find((object) =\u003e urlPathFromFilePath(object?.__metadata?.relSourcePath) === urlPath);\n         return { props };\n     }\n     ```\n\n5. When working locally, you might want the browser to automatically reflect any content changes.\n   To do that, wrap your pages with the following higher order component:\n\n    ```js\n    import { withRemoteDataUpdates } from 'sourcebit-target-next/with-remote-data-updates';\n\n    class Page extends React.Component {\n        render() {\n            // ...\n        }\n    }\n\n    export default withRemoteDataUpdates(Page);\n    ```\n\n## Sourcebit Configuration\n\nThis plugin can be configured with several options:\n\n```js\n// sourcebit.js\n\nconst isDev = process.env.NODE_ENV === 'development';\n\nmodule.exports = {\n    plugins: [\n        // ...otherPlugins,\n        {\n            module: require('sourcebit-target-next'),\n            options: {\n                liveUpdate: isDev,\n                cacheFilePath: path.join(__dirname, '.custom-filename.json'),\n                disableCache: false,\n                flattenAssetUrls: true\n            }\n        }\n    ]\n};\n```\n\n- `liveUpdate` (boolean) A flag indicating if page should reload its data when the underlying content changes.\n   Defaults to `true` when `NODE_ENV` is set to `development`.\n- `cacheFilePath` (string) A file path for cached data, default is `.sourcebit-nextjs-cache.json`\n- `disableCache` (boolean) A flag indicating if plugin should produce the cache file. Note, if you set this flag to true\n  you won't be able to use `sourcebitDataClient` to consume the data and will have to call `sourcebit.fetch()` for every page.\n- `flattenAssetUrls` (boolean) Some source plugins might return complex objects for linked assets. Set this flag to `true`\n  to replace these objects with a string representing the absolute asset URL.\n\nYou can check out an [example project](https://github.com/stackbit-themes/stackbit-sanity-starter) that uses\n`sourcebit-source-sanity` and `sourcebit-target-next` plugins to fetch the data from [Sanity.io](https://www.sanity.io/)\nand consume it inside Next.js pages.\n\n## Tips\n\nAdd following to your `.gitignore`:\n\n```\n.sourcebit-nextjs-cache.json\n```\n\nTo simplify the dynamic routing architecture and to allow greater flexibility\nwhen creating pages in Headless CMS, we advise using following pattern:\n\n`pages/[[...slug]].js`\n\n```js\nimport React from 'react';\nimport { sourcebitDataClient } from 'sourcebit-target-next';\nimport { withRemoteDataUpdates } from 'sourcebit-target-next/with-remote-data-updates';\nimport pageLayouts from '../layouts';\n\nclass Page extends React.Component {\n    render() {\n        // every page can have different layout, pick the layout based on the \"layout\" property of the page\n        const PageLayout = pageLayouts[_.get(this.props, 'page.layout')];\n        return \u003cPageLayout {...this.props} /\u003e;\n    }\n}\n\nexport default withRemoteDataUpdates(Page);\n\nexport async function getStaticPaths() {\n    const data = await sourcebitDataClient.getData();\n    const paths = data.objects\n        // find objects loaded from the \"pages\" folder (__metadata.sourceName === \"pages\")\n        .filter((object) =\u003e object?.__metadata?.sourceName === 'pages')\n        // map the file path to the page url, e.g.: 'about.md' =\u003e '/about'\n        .map((object) =\u003e urlPathFromFilePath(object?.__metadata?.relSourcePath))\n    return {\n        paths,\n        fallback: false\n    };\n}\n\nexport async function getStaticProps({ params }) {\n    const urlPath = '/' + (params?.slug || []).join('/');\n    const data = await sourcebitDataClient.getData();\n    // find the objects corresponding to the requested page\n    const props = data.objects.find((object) =\u003e urlPathFromFilePath(object?.__metadata?.relSourcePath) === urlPath);\n    return { props };\n}\n```\n\n[Next.js SSG capabilities]: https://nextjs.org/blog/next-9-3#next-gen-static-site-generation-ssg-support\n[sourcebit-source-filesystem]: https://github.com/stackbit/sourcebit-source-filesystem\n[sourcebit-source-contentful]: https://github.com/stackbit/sourcebit-source-contentful\n[sourcebit-source-sanity]: https://github.com/stackbit/sourcebit-source-sanity\n[getStaticProps]: https://nextjs.org/docs/basic-features/data-fetching#getstaticprops-static-generation\n[getStaticPaths]: https://nextjs.org/docs/basic-features/data-fetching#getstaticpaths-static-generation\n[dynamic routes]: https://nextjs.org/docs/routing/dynamic-routes\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstackbit%2Fsourcebit-target-next","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fstackbit%2Fsourcebit-target-next","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstackbit%2Fsourcebit-target-next/lists"}