{"pageProps":{"post":{"source":{"compiledSource":"/*@jsxRuntime automatic @jsxImportSource react*/\nconst {Fragment: _Fragment, jsx: _jsx, jsxs: _jsxs} = arguments[0];\nconst {useMDXComponents: _provideComponents} = arguments[0];\nfunction _createMdxContent(props) {\n const _components = Object.assign({\n p: \"p\",\n h2: \"h2\",\n ul: \"ul\",\n li: \"li\",\n a: \"a\",\n code: \"code\",\n ol: \"ol\",\n pre: \"pre\",\n span: \"span\"\n }, _provideComponents(), props.components), {Image} = _components;\n if (!Image) _missingMdxReference(\"Image\", true);\n return _jsxs(_Fragment, {\n children: [_jsx(_components.p, {\n children: \"Are you a Next.js developer who doesn't want to hassle with managing a backend server solely for handling your database ? Or maybe you don't want to pay for hosting your database when you'll be working with a relatively small amount of data?\"\n }), \"\\n\", _jsx(_components.p, {\n children: \"That was recently the case for me with an app that didn't require an entire complex architecture and wasn't going to receive millions of users (which is often the case for any beta version of an app, by the way).\"\n }), \"\\n\", _jsx(_components.p, {\n children: \"I found a super simple solution that I was able to implement in just a few minutes. It allows me to keep the app frontend-only without managing a server (by leveraging Next.js serverless functions, easily and freely hosted on Vercel). It's incredibly straightforward to set up and use, and it integrates seamlessly with Next.js. The solution I'm talking about is Airtable.\"\n }), \"\\n\", _jsx(_components.p, {\n children: \"Airtable is like a \\\"super Excel\\\" that enables you to easily store and manage data in various views. It is widely recognized and used, particularly in the No-Code/Low-Code sphere, thanks to its integration simplicity.\"\n }), \"\\n\", _jsx(_components.p, {\n children: \"Here, I'll show you how I implemented Airtable in my app to retrieve user emails.\"\n }), \"\\n\", _jsx(_components.h2, {\n id: \"setting-up-a-table-in-airtable\",\n children: \"Setting Up a Table in Airtable\"\n }), \"\\n\", _jsx(_components.p, {\n children: \"The first step is to create an Airtable account and set up a table.\\nTo interact with Airtable, you'll need three things:\"\n }), \"\\n\", _jsxs(_components.ul, {\n children: [\"\\n\", _jsx(_components.li, {\n children: \"An API key\"\n }), \"\\n\", _jsx(_components.li, {\n children: \"The Base ID\"\n }), \"\\n\", _jsx(_components.li, {\n children: \"The table name\"\n }), \"\\n\"]\n }), \"\\n\", _jsx(_components.p, {\n children: \"To get started, create a Base in Airtable:\"\n }), \"\\n\", _jsx(Image, {\n src: \"/assets/articles/airtable-db-in-next/create-base.png\",\n layout: \"fill\"\n }), \"\\n\", _jsx(_components.h2, {\n id: \"obtaining-the-api-key\",\n children: \"Obtaining the API Key\"\n }), \"\\n\", _jsxs(_components.p, {\n children: [\"To obtain the API key, go to \", _jsx(_components.a, {\n href: \"https://airtable.com/create/tokens\",\n children: \"https://airtable.com/create/tokens\"\n }), \".\"]\n }), \"\\n\", _jsx(_components.p, {\n children: \"Then, create a new \\\"Personal access token\\\" and provide the following scope:\"\n }), \"\\n\", _jsxs(_components.ul, {\n children: [\"\\n\", _jsx(_components.li, {\n children: _jsx(_components.code, {\n children: \"schema.bases:read\"\n })\n }), \"\\n\", _jsx(_components.li, {\n children: _jsx(_components.code, {\n children: \"data.records:read\"\n })\n }), \"\\n\", _jsx(_components.li, {\n children: _jsx(_components.code, {\n children: \"data.records:write\"\n })\n }), \"\\n\"]\n }), \"\\n\", _jsx(Image, {\n src: \"/assets/articles/airtable-db-in-next/create-token.png\",\n layout: \"fill\"\n }), \"\\n\", _jsx(_components.h2, {\n id: \"obtaining-the-base-id\",\n children: \"Obtaining the Base ID\"\n }), \"\\n\", _jsx(_components.p, {\n children: \"Once the table is created, you can find the table name (which can be changed) at the top left corner. To retrieve the Base ID:\"\n }), \"\\n\", _jsxs(_components.ol, {\n children: [\"\\n\", _jsx(_components.li, {\n children: \"Set up the structure of your data.\"\n }), \"\\n\", _jsx(_components.li, {\n children: \"Click on the \\\"Help\\\" or \\\"Aide\\\" button in the top right corner.\"\n }), \"\\n\", _jsx(_components.li, {\n children: \"A popup will appear; click on \\\"API Documentation.\\\"\"\n }), \"\\n\"]\n }), \"\\n\", _jsx(Image, {\n src: \"/assets/articles/airtable-db-in-next/go-to-api-doc.png\",\n layout: \"fill\"\n }), \"\\n\", _jsx(_components.p, {\n children: \"You'll be redirected to a page where you can find the Base ID.\"\n }), \"\\n\", _jsx(Image, {\n src: \"/assets/articles/airtable-db-in-next/get-base-id-from-doc.png\",\n layout: \"fill\"\n }), \"\\n\", _jsx(_components.p, {\n children: \"Now we have everything we need to interact with Airtable from our Next.js app.\"\n }), \"\\n\", _jsx(_components.h2, {\n id: \"protecting-this-information\",\n children: \"Protecting this Information\"\n }), \"\\n\", _jsxs(_components.p, {\n children: [\"Sensitive information such as the API key or Base ID should not be exposed to the public. Make sure to store these details in your \", _jsx(_components.code, {\n children: \".env.local\"\n }), \" file during development, and configure them as environment variables with your chosen hosting provider (if you're using Git, remember to add the \", _jsx(_components.code, {\n children: \".env.local\"\n }), \" file to your \", _jsx(_components.code, {\n children: \".gitignore\"\n }), \" as well).\"]\n }), \"\\n\", _jsx(_components.h2, {\n id: \"creating-an-abstraction-to-interact-with-airtable\",\n children: \"Creating an Abstraction to Interact with Airtable\"\n }), \"\\n\", _jsx(_components.p, {\n children: \"To start using Airtable, we'll use the official JavaScript SDK:\"\n }), \"\\n\", _jsx(_components.pre, {\n children: _jsx(_components.code, {\n className: \"hljs language-bash\",\n children: \"npm install airtable // OR yarn add airtable\\n\"\n })\n }), \"\\n\", _jsx(_components.p, {\n children: \"To manipulate the SDK,\"\n }), \"\\n\", _jsx(_components.p, {\n children: \"we'll create a simple abstraction that allows us to retrieve, add, delete, or modify data in our table:\"\n }), \"\\n\", _jsx(_components.pre, {\n children: _jsxs(_components.code, {\n className: \"hljs language-jsx\",\n children: [_jsx(_components.span, {\n className: \"hljs-keyword\",\n children: \"import\"\n }), \" \", _jsx(_components.span, {\n className: \"hljs-title class_\",\n children: \"AirtableLib\"\n }), \" \", _jsx(_components.span, {\n className: \"hljs-keyword\",\n children: \"from\"\n }), \" \", _jsx(_components.span, {\n className: \"hljs-string\",\n children: \"'airtable'\"\n }), \"\\n\\n\", _jsx(_components.span, {\n className: \"hljs-keyword\",\n children: \"const\"\n }), \" \", _jsx(_components.span, {\n className: \"hljs-title function_\",\n children: \"getRecordsFields\"\n }), \" = records => records?.\", _jsx(_components.span, {\n className: \"hljs-title function_\",\n children: \"map\"\n }), \"(\", _jsxs(_components.span, {\n className: \"hljs-function\",\n children: [_jsx(_components.span, {\n className: \"hljs-params\",\n children: \"record\"\n }), \" =>\"]\n }), \" record?.\", _jsx(_components.span, {\n className: \"hljs-property\",\n children: \"fields\"\n }), \")\\n\\n\", _jsx(_components.span, {\n className: \"hljs-keyword\",\n children: \"export\"\n }), \" \", _jsx(_components.span, {\n className: \"hljs-keyword\",\n children: \"class\"\n }), \" \", _jsx(_components.span, {\n className: \"hljs-title class_\",\n children: \"AirtableTable\"\n }), \" {\\n #table\\n\\n \", _jsx(_components.span, {\n className: \"hljs-title function_\",\n children: \"constructor\"\n }), \"(\", _jsx(_components.span, {\n className: \"hljs-params\",\n children: \"{ baseId, tableName }\"\n }), \") {\\n \", _jsx(_components.span, {\n className: \"hljs-variable language_\",\n children: \"this\"\n }), \".#table = \", _jsx(_components.span, {\n className: \"hljs-variable language_\",\n children: \"this\"\n }), \".#\", _jsx(_components.span, {\n className: \"hljs-title function_\",\n children: \"getTable\"\n }), \"({ baseId, tableName })\\n }\\n\\n #\", _jsx(_components.span, {\n className: \"hljs-title function_\",\n children: \"getTable\"\n }), \"(\", _jsx(_components.span, {\n className: \"hljs-params\",\n children: \"{ baseId, tableName }\"\n }), \") {\\n \", _jsx(_components.span, {\n className: \"hljs-title class_\",\n children: \"AirtableLib\"\n }), \".\", _jsx(_components.span, {\n className: \"hljs-title function_\",\n children: \"configure\"\n }), \"({\\n \", _jsx(_components.span, {\n className: \"hljs-attr\",\n children: \"apiKey\"\n }), \": process.\", _jsx(_components.span, {\n className: \"hljs-property\",\n children: \"env\"\n }), \".\", _jsx(_components.span, {\n className: \"hljs-property\",\n children: \"AIRTABLE_API_KEY\"\n }), \"\\n })\\n\\n \", _jsx(_components.span, {\n className: \"hljs-keyword\",\n children: \"const\"\n }), \" base = \", _jsx(_components.span, {\n className: \"hljs-title class_\",\n children: \"AirtableLib\"\n }), \".\", _jsx(_components.span, {\n className: \"hljs-title function_\",\n children: \"base\"\n }), \"(baseId)\\n \", _jsx(_components.span, {\n className: \"hljs-keyword\",\n children: \"const\"\n }), \" table = \", _jsx(_components.span, {\n className: \"hljs-title function_\",\n children: \"base\"\n }), \"(tableName)\\n\\n \", _jsx(_components.span, {\n className: \"hljs-keyword\",\n children: \"return\"\n }), \" table\\n }\\n\\n \", _jsx(_components.span, {\n className: \"hljs-keyword\",\n children: \"async\"\n }), \" \", _jsx(_components.span, {\n className: \"hljs-title function_\",\n children: \"getRecords\"\n }), \"(\", _jsx(_components.span, {\n className: \"hljs-params\"\n }), \") {\\n \", _jsx(_components.span, {\n className: \"hljs-comment\",\n children: \"// ℹ️ Get the first 100 records\"\n }), \"\\n \", _jsx(_components.span, {\n className: \"hljs-keyword\",\n children: \"const\"\n }), \" records = \", _jsx(_components.span, {\n className: \"hljs-keyword\",\n children: \"await\"\n }), \" \", _jsx(_components.span, {\n className: \"hljs-variable language_\",\n children: \"this\"\n }), \".#table.\", _jsx(_components.span, {\n className: \"hljs-title function_\",\n children: \"select\"\n }), \"({}).\", _jsx(_components.span, {\n className: \"hljs-title function_\",\n children: \"firstPage\"\n }), \"()\\n \", _jsx(_components.span, {\n className: \"hljs-keyword\",\n children: \"return\"\n }), \" \", _jsx(_components.span, {\n className: \"hljs-title function_\",\n children: \"getRecordsFields\"\n }), \"(records)\\n }\\n\\n \", _jsx(_components.span, {\n className: \"hljs-keyword\",\n children: \"async\"\n }), \" \", _jsx(_components.span, {\n className: \"hljs-title function_\",\n children: \"addRecord\"\n }), \"(\", _jsx(_components.span, {\n className: \"hljs-params\",\n children: \"fields\"\n }), \") {\\n \", _jsx(_components.span, {\n className: \"hljs-keyword\",\n children: \"const\"\n }), \" addedRecords = \", _jsx(_components.span, {\n className: \"hljs-keyword\",\n children: \"await\"\n }), \" \", _jsx(_components.span, {\n className: \"hljs-variable language_\",\n children: \"this\"\n }), \".#table.\", _jsx(_components.span, {\n className: \"hljs-title function_\",\n children: \"create\"\n }), \"([\\n {\\n fields\\n }\\n ])\\n\\n \", _jsx(_components.span, {\n className: \"hljs-keyword\",\n children: \"return\"\n }), \" \", _jsx(_components.span, {\n className: \"hljs-title function_\",\n children: \"getRecordsFields\"\n }), \"(addedRecords)?.[\", _jsx(_components.span, {\n className: \"hljs-number\",\n children: \"0\"\n }), \"]\\n }\\n\\n \", _jsx(_components.span, {\n className: \"hljs-keyword\",\n children: \"async\"\n }), \" \", _jsx(_components.span, {\n className: \"hljs-title function_\",\n children: \"updateRecord\"\n }), \"(\", _jsx(_components.span, {\n className: \"hljs-params\",\n children: \"{ id, fields }\"\n }), \") {\\n \", _jsx(_components.span, {\n className: \"hljs-keyword\",\n children: \"const\"\n }), \" updatedRecords = \", _jsx(_components.span, {\n className: \"hljs-keyword\",\n children: \"await\"\n }), \" \", _jsx(_components.span, {\n className: \"hljs-variable language_\",\n children: \"this\"\n }), \".#table.\", _jsx(_components.span, {\n className: \"hljs-title function_\",\n children: \"update\"\n }), \"([\\n {\\n id,\\n fields\\n }\\n ])\\n \", _jsx(_components.span, {\n className: \"hljs-keyword\",\n children: \"return\"\n }), \" \", _jsx(_components.span, {\n className: \"hljs-title function_\",\n children: \"getRecordsFields\"\n }), \"(updatedRecords)?.[\", _jsx(_components.span, {\n className: \"hljs-number\",\n children: \"0\"\n }), \"]\\n }\\n\\n \", _jsx(_components.span, {\n className: \"hljs-keyword\",\n children: \"async\"\n }), \" \", _jsx(_components.span, {\n className: \"hljs-title function_\",\n children: \"deleteRecords\"\n }), \"(\", _jsx(_components.span, {\n className: \"hljs-params\",\n children: \"ids\"\n }), \") {\\n \", _jsx(_components.span, {\n className: \"hljs-keyword\",\n children: \"const\"\n }), \" deletedRecords = \", _jsx(_components.span, {\n className: \"hljs-keyword\",\n children: \"await\"\n }), \" \", _jsx(_components.span, {\n className: \"hljs-variable language_\",\n children: \"this\"\n }), \".#table.\", _jsx(_components.span, {\n className: \"hljs-title function_\",\n children: \"destroy\"\n }), \"(ids)\\n \", _jsx(_components.span, {\n className: \"hljs-keyword\",\n children: \"return\"\n }), \" \", _jsx(_components.span, {\n className: \"hljs-title function_\",\n children: \"getRecordsFields\"\n }), \"(deletedRecords)?.[\", _jsx(_components.span, {\n className: \"hljs-number\",\n children: \"0\"\n }), \"]\\n }\\n}\\n\"]\n })\n }), \"\\n\", _jsx(_components.p, {\n children: \"That's about it! You can now interact with the table in this manner, for example, from an API route:\"\n }), \"\\n\", _jsx(_components.pre, {\n children: _jsxs(_components.code, {\n className: \"hljs language-jsx\",\n children: [_jsx(_components.span, {\n className: \"hljs-keyword\",\n children: \"export\"\n }), \" \", _jsx(_components.span, {\n className: \"hljs-keyword\",\n children: \"default\"\n }), \" \", _jsx(_components.span, {\n className: \"hljs-keyword\",\n children: \"function\"\n }), \" \", _jsx(_components.span, {\n className: \"hljs-title function_\",\n children: \"getUsers\"\n }), \"(\", _jsx(_components.span, {\n className: \"hljs-params\",\n children: \"req, res\"\n }), \") {\\n \", _jsx(_components.span, {\n className: \"hljs-keyword\",\n children: \"const\"\n }), \" usersTable = \", _jsx(_components.span, {\n className: \"hljs-keyword\",\n children: \"new\"\n }), \" \", _jsx(_components.span, {\n className: \"hljs-title class_\",\n children: \"AirtableTable\"\n }), \"({\\n \", _jsx(_components.span, {\n className: \"hljs-attr\",\n children: \"baseId\"\n }), \": process.\", _jsx(_components.span, {\n className: \"hljs-property\",\n children: \"env\"\n }), \".\", _jsx(_components.span, {\n className: \"hljs-property\",\n children: \"AIRTABLE_BASE_ID\"\n }), \",\\n \", _jsx(_components.span, {\n className: \"hljs-attr\",\n children: \"tableName\"\n }), \": \", _jsx(_components.span, {\n className: \"hljs-string\",\n children: \"'YOUR_TABLE_NAME'\"\n }), \"\\n })\\n\\n \", _jsx(_components.span, {\n className: \"hljs-keyword\",\n children: \"const\"\n }), \" users = \", _jsx(_components.span, {\n className: \"hljs-keyword\",\n children: \"await\"\n }), \" usersTable.\", _jsx(_components.span, {\n className: \"hljs-title function_\",\n children: \"getRecords\"\n }), \"()\\n res.\", _jsx(_components.span, {\n className: \"hljs-title function_\",\n children: \"json\"\n }), \"(users)\\n}\\n\"]\n })\n })]\n });\n}\nfunction MDXContent(props = {}) {\n const {wrapper: MDXLayout} = Object.assign({}, _provideComponents(), props.components);\n return MDXLayout ? _jsx(MDXLayout, Object.assign({}, props, {\n children: _jsx(_createMdxContent, props)\n })) : _createMdxContent(props);\n}\nreturn {\n default: MDXContent\n};\nfunction _missingMdxReference(id, component) {\n throw new Error(\"Expected \" + (component ? \"component\" : \"object\") + \" `\" + id + \"` to be defined: you likely forgot to import, pass, or provide it.\");\n}\n","frontmatter":{},"scope":{}},"meta":{"slug":"use-airtable-as-db-in-next","title":"How to use Airtable as your database with Next.js?","desc":"Using Airtable as your database with Next.js, a step-by-step guide","image":"","date":"Tue Mar 15 2022 00:00:00 GMT+0000 (Coordinated Universal Time)","keywords":"Airtable, Next.js, Databases"}}},"__N_SSG":true}