
Bringing Dynamic Content to 11ty with Slinkity and GraphQL
Ben Holmes demonstrates integrating Slinkity with StepZen to create a full-stack Jamstack application using React components and a PostgreSQL database
Episode Description
Ben Holmes demos Slinkity, an Eleventy-Vite framework, while Anthony Campolo connects it to a Supabase database via StepZen's GraphQL API.
Episode Summary
Anthony Campolo and Ben Holmes walk through building a full stack Jamstack project by combining Slinkity, StepZen, and Supabase from scratch. The stream opens with Ben explaining what Eleventy is — an unopinionated static site generator — and how Slinkity acts as glue between Eleventy and the Vite bundler, adding JavaScript compilation, hot reloading, and component support to an otherwise template-focused tool. They discuss islands architecture and the philosophy of opting into JavaScript rather than opting out of a massive single page app bundle. From there, Anthony scaffolds a Slinkity project, sets up a React component rendered through Eleventy shortcodes, and then introduces StepZen as a way to create a deployed GraphQL endpoint. After confirming the setup with mock data, they spin up a Supabase Postgres database, populate it with a books table, and wire the REST endpoint into StepZen's schema. The final result is a React component fetching live database records through GraphQL and rendering them on a static page. Along the way, they discuss current limitations around environment variable exposure on the front end, the promise of Eleventy serverless for secure API key handling, and draw comparisons to Gatsby's data layer. The conversation closes with thoughts on framework collaboration — particularly between Slinkity and Astro — and the evolving landscape of transitional apps that blend single page and multi page approaches.
Chapters
00:00:00 - Introducing Ben Holmes and the Slinkity Project
Anthony Campolo welcomes Ben Holmes to the StepZen stream and asks him to introduce himself. Ben describes his role as a full stack developer at Peloton and as the maintainer of Slinkity, an open source project that bridges Eleventy and the Vite bundler.
Anthony sets the stage by noting that they recently recorded a podcast episode about Slinkity and plan to build a full stack Jamstack project live on stream. He explains that Slinkity builds on top of Eleventy and teases the spooky theme shared across the hosts' online handles before moving into the technical discussion.
00:01:59 - What Is Eleventy and Why Build on It
Ben explains that Eleventy is an unopinionated static site generator in the JavaScript ecosystem, comparable to Jekyll or Hugo but with JavaScript-based plugins. It pulls data from various sources into a cascade accessible by pages and routes, and compiles any templating language — Markdown, Nunjucks, Liquid, Vue — into HTML. However, it has no built-in opinions on styling or JavaScript bundling.
This gap is exactly what Slinkity fills. By bolting the Vite bundler onto Eleventy, Slinkity handles JavaScript compilation, CSS processing, and fast development reloads while letting developers keep their existing Eleventy templates and workflows intact. Anthony adds context about Vite's browser-level, on-demand bundling approach compared to webpack's full-site bundling model, noting that Vite's speed is a major advantage.
00:06:11 - Islands Architecture and JavaScript Philosophy
Anthony introduces the concept of islands architecture, credited to Jason Miller, which advocates for placing interactive JavaScript only where it's needed on a page rather than shipping an entire single page app. He draws a connection to the older "JavaScript sprinkles" idea from the Rails community and references Ben's food metaphor of salads versus burgers to illustrate the balance.
Ben expands on this by arguing that the islands approach lets developers opt into JavaScript incrementally rather than starting with a massive bundle and trying to optimize it away. He contrasts this with single page app frameworks where developers must use techniques like server components or memoization to reduce what ships to the browser, framing Slinkity's approach as a more intentional way to control page weight.
00:08:01 - Scaffolding the Slinkity Project from Scratch
Anthony begins building the project live, creating a blank directory with a git ignore, an Eleventy config file, and basic package scripts for serve and build commands. Ben explains that the Eleventy config simply tells the tool where to find the source directory, and Slinkity is smart enough to follow that same convention automatically.
They spin up the dev server and see a bare markdown index page rendering. Anthony then introduces a React JSX component and demonstrates how Slinkity uses Eleventy shortcodes to hydrate React components into any template. After a brief detour to fix a file path issue involving the includes folder — which Ben explains serves as a components directory that keeps non-route files separate — the hello component renders successfully on the page.
00:15:00 - Setting Up the StepZen GraphQL Endpoint
After greeting community members in the chat, Anthony shifts to explaining StepZen and the concept of full stack Jamstack — augmenting static front ends with real backend capabilities. He creates an index GraphQL file with a simple test query that returns mock JSON data, then runs the StepZen start command to deploy the endpoint.
They confirm the mock query works through the GraphiQL editor and note that the endpoint is actually deployed remotely on StepZen's infrastructure, not just running locally. Anthony then walks through a standard React fetch pattern using useEffect and useState to send a GraphQL POST request, stringify the query body, and render the response on the page — demonstrating basic React data fetching wired to a GraphQL API.
00:22:21 - Rendering Data and Discussing Improvements
With the test string successfully displayed on the page, Anthony acknowledges this is a proof of concept lacking loading and error states. Ben suggests React Query as a way to abstract the fetch logic, and Anthony notes the distinction between using React Query with raw fetch versus the GraphQL Request library for cleaner query handling.
Ben also highlights that Eleventy's data files could perform this fetch at build time, eliminating the need for a client-side loading spinner entirely. They discuss the current limitation that the API key is exposed in the front end bundle, making deployment unsafe, and point to Eleventy serverless as the upcoming solution for hiding secrets server-side. This frames the project as a development preview rather than a production-ready application.
00:26:35 - Connecting Supabase as the Database
Anthony spins up a Supabase project, explaining that it provides a managed Postgres database with RESTful APIs via PostgREST. He creates a books table through the Supabase UI, inserts test rows, and then configures StepZen to consume the Supabase REST endpoint using its REST connector directive and a config YAML file for the API key.
After running stepzen start, they execute a query that returns the books data from the live Postgres database. Ben asks about query customization, and Anthony explains that StepZen uses declarative directives instead of hand-written resolvers, allowing developers to chain queries together or create relationships between data sources without traditional resolver code. The full pipeline — Supabase Postgres to REST to StepZen GraphQL to React — is now operational.
00:33:14 - Full Stack Jamstack Philosophy and Flexibility
Anthony reflects on how this project exemplifies full stack Jamstack: a static, decoupled front end connected to a developer-owned Postgres database through a GraphQL gateway, without relying on a third-party CMS. He highlights StepZen's flexibility, noting it can consume REST endpoints, native GraphQL endpoints, or direct SQL via its DB query directive — giving developers multiple paths to connect any Postgres database.
Ben draws a comparison to Gatsby's GraphQL data layer, where all data sources funnel through a unified query interface, but notes that StepZen creates actual deployable endpoints rather than build-time-only queries. They discuss the "front of the front end" through "back of the back end" mental model for decomposing full stack architecture, and Anthony shares how this framing would have helped during his bootcamp experience.
00:42:37 - Gatsby Comparisons and the GraphQL Data Layer
Ben shares his experience with Gatsby, recalling that the image optimization plugin was the main draw for most users, while the GraphQL layer for accessing even local assets felt unusual but powerful for controlling what ships to end users. Anthony agrees, noting his co-host had the same gateway experience through the Gatsby image component.
Anthony positions the day's project as a more modern, greenfield approach to the same idea Gatsby pioneered — combining GraphQL data fetching with static generation and partial hydration — but built on newer, lighter tools without the accumulated plugin ecosystem issues. He sees Slinkity paired with StepZen as an early but promising alternative for developers who want this pattern without Gatsby's overhead.
00:45:28 - Future Plans, Framework Collaboration, and Closing
Ben outlines upcoming Slinkity features: shared state between component islands, serverless function support for fresh data on each page load, and the ability to selectively link pages into mini single page apps within a multi-page site. He references Rich Harris's talk on transitional apps as evidence that the industry is converging on flexible approaches rather than committing fully to either SPA or MPA paradigms.
Anthony reveals that the Slinkity and Astro teams are actively collaborating, countering the notion of framework wars by emphasizing that teams working on similar problems benefit from sharing approaches. They close by dropping links to their respective projects and social accounts, encouraging viewers to check out the contributing guide, and promising example repositories combining Slinkity, StepZen, and Supabase in the coming weeks.
Transcript
00:00:24 - Anthony Campolo
I'm always grooving to that little countdown music. Hello everybody, this is the StepZen stream. We have a very special guest, Ben Goulmes. Hello, Ben Holmes. So why don't you go ahead and introduce yourself to our audience.
00:00:43 - Ben Holmes
Yes, Ben Goulms is my nighttime personality. Normally I go by Ben Holmes. I am a full stack developer doing a whole bunch of web dev stuff over at Peloton right now, and I'm the maintainer of this little open source foray called Slinkity, which I'm sure we'll get into today.
00:01:01 - Anthony Campolo
Foray. That's a good word. So, yeah, Slinkity is a very cool, hip new open source project and it's something that I've been helping out a little bit with as you've been getting it going. And just yesterday, actually, we had an FSJAM episode air about it, which is especially exciting because we're going to be building what I would consider to be an FSJAM project with Slinkity today. But we can kind of get into all that as we go. So we should first set the stage for any viewers who may not be familiar with Eleventy. Slinkity is a framework that is heavily built on Eleventy. Love the spooky names. Yeah, we got AJC, SpiderWebDev, and Ben Goulms here with you, giving you some spooky web dev content today. So let's talk a little about Eleventy. What is Eleventy and why did you decide to build upon it instead of doing your own thing entirely?
00:01:59 - Ben Holmes
Exactly. And I was doing my own thing for a little bit just because I didn't know what Eleventy was. And I thought, oh, if you want to go into this world of like, I want to compile my favorite framework into a static site, you've got to build from scratch, which is the approach that Astro took as well. It's something that we take a lot of inspiration from, so I definitely call it out. But Eleventy is honestly two things. The first thing it's really good at — well, it's a static site generator first and foremost, and it's a very unopinionated one that is able to connect to any source of data through a CMS connection or something through JavaScript. If you've used something like Jekyll or Hugo, it's a very similar tool to that, except now you're using JavaScript and JavaScript plugins. So if you're an existing web developer, you probably feel more confident writing your own plugins for this tool. It's able to pull in data into a whole cascade — a global data file that all of your pages can access, or pages that only one route can access, or a whole directory of routes — all sorts of things to aggregate information, which is the core part of Jamstack.
00:03:09 - Ben Holmes
At the build time layer, Eleventy has a setup to compile any templating language you want. If you want to use Vue to write a page, or you want to use Markdown, Nunjucks, Liquid — all of the standard server side templates that we've been using for decades — it'll help you compile that to a standard page as well. The one piece that's missing, of course, is it has no opinions on styling. So if you want to compile Sass or Tailwind or any custom setup, you've got to do that yourself. There are a number of plugins for it, but it's not included out of the box. And also compiling JavaScript — it has no opinions on that. It's only going to compile HTML templates to more HTML. It's not going to bundle anything for you. It's not going to have live reloading, or certainly not hot module reloading, which is a popular term. This project, Slinkity, is trying to bolt an existing bundler called Vite into your Eleventy flow. You can keep doing what you're doing with Eleventy already — bring your templates, bring your styles, whatever setup you like, because it's so flexible — then just compile any bit of JavaScript or CSS as well, using the Vite bundler.
00:04:17 - Ben Holmes
So that's the setup.
00:04:19 - Anthony Campolo
We don't need to go super deep into it. But Vite is a newer generation version of what we traditionally think of as a tool like webpack or even Rollup. It actually uses Rollup, but it's a way to compile or transpile things like JSX and Vue and different Svelte templates, and basically take that and turn it into HTML and vanilla JavaScript. Then you'll have a bundle that you can actually ship to the browser, because we're going to be writing lots of code that the browser doesn't necessarily understand — it's in all these different syntaxes and languages that are kind of bespoke to specific frameworks. But Vite is really cool because it lets you deal with all of those frameworks collectively in a way that lets you pick and choose which ones you want to use, where you want to use them.
00:05:11 - Ben Holmes
Yeah, exactly. And it's unique in that it's doing it from the browser level, where it's like, when I visit a route, I want to bundle the resources for that route. Whereas webpack was like, I want to bundle my whole site and then I'm going to look at it in my browser — which means if you have a ton of pages on your site, you're going to be waiting forever while you're trying to work in development. But Vite's like, no, we're going to wait for you to visit that page. We'll use the HTML file as the entry point to decide what you want to see, and then we'll show it to you with whatever compilers we have out of the box or whatever plugins you configure — like, here's how React works, here's how CSS Modules works, here's how Tailwind works. Any dependency that you want. So it's a new way of thinking about bundling.
00:05:52 - Anthony Campolo
Yeah. And as Lucia is saying in the chat, it is very, very fast —
00:05:56 - Ben Holmes
— which is quite nice, as the French say. Yes, Vite is French for fast.
00:06:01 - Anthony Campolo
As the French say, hurry up, hurry up.
00:06:07 - Ben Holmes
Yeah, it's not pronounced "veit," by the way.
00:06:11 - Anthony Campolo
Yeah. And then the last thing that we should kind of mention is there's this term islands architecture, which was a term pioneered by Jason Miller, who's the creator of Preact and wmr, which is another kind of new generation build tool. And this is the idea of only using specific pieces of JavaScript where you need them on the page or on your website. If you can section it out into little islands of interactivity — I actually think the original term for this was "JavaScript sprinkles." This is what the people back in the Ruby on Rails days used to say. You would want to have just little sprinkles of JavaScript that you put everywhere. And so an island of JavaScript is much like a sprinkle of JavaScript. You just want a little bit of JavaScript. You don't want too much because you can kind of get overboard with it. And you had a really great food metaphor to talk about this. You have your salads, which are your very light, healthy HTML, and then your huge beefy JavaScript burgers. And so you just want to have a little bit of burger.
00:07:21 - Ben Holmes
It's that you just want a little chopped chicken on top of your salad. You don't want to eat a burger every day. I totally agree. That's the Jamstack Conference, by the way, for those unaware. But yeah, it's a cool setup. And I feel like "sprinkles" kind of scares people away — like, well, I don't have a sprinkle. My component's pretty big. I don't know. And it's like, you can put however much you want. It should be up to you to opt into how much JavaScript you want on the page, instead of: we're going to ship the whole hog single page app and then you've got to opt out with clever server components and useMemo — those are the terms to opt out. I think this is a way to opt in and choose how much JavaScript you need.
00:08:01 - Anthony Campolo
And then we're going to start building out this project here. I'm going to start totally from scratch with just a blank, empty directory. And we're going to set up our Slinkity project and show what goes along with it. I'm just going to create a couple boilerplate pieces here, which is going to be a .gitignore for all of our node modules, our config which is going to have our keys, and then our Eleventy site itself, which is going to be kind of built on the fly. We're also going to have a StepZen endpoint that we're going to use to deploy our actual endpoint. We're going to have a config YAML for our keys, and as we get into these, we'll talk about them a little bit more. If you're not familiar at all with StepZen or Slinkity, there might be some things that are a little bit confusing here, so we'll try our best not to run through everything too fast. But the first thing we're going to do is just build up a Slinkity project. Let's not talk about any of the StepZen stuff yet and just talk about what is a basic Slinkity project — it's much like an Eleventy project.
00:09:10 - Anthony Campolo
Is that right?
00:09:12 - Ben Holmes
Yeah, it's the same out of the box. If you use one of the Eleventy starter templates, you can even use that as a base and start using Slinkity on top of it.
00:09:21 - Anthony Campolo
That's all we have to be aware of — we're using the 11ty 1.0 beta. What exactly does that mean?
00:09:30 - Ben Holmes
It means it's got shiny features that may or may not break. They shouldn't — it's been very stable from my experience, but it enables some cool things. Like, we allow you to write entire pages using JSX. So if you wanted to ship the whole hog and use React for your whole experience, you can do that. And that's using Eleventy's custom extensions helper that lets us define JSX, and that's a beta feature. That's the main reason we use it — to reach for that.
00:09:58 - Anthony Campolo
Okay, yeah, that makes sense. And as I've been building stuff out with these tools, I have found that the Eleventy beta hasn't gotten in my way at all. And I think it's because Eleventy itself is actually very stable, despite not being quote unquote 1.0. Yeah, I think that Zach, the creator, is someone who is very cautious in terms of when he says something is in release.
00:10:23 - Ben Holmes
I know, yeah.
00:10:24 - Anthony Campolo
And 1.0 and production ready. So this is actually further along than you might think based on the beta tag — to the point where you can build a whole framework on top of it. And we should talk a little bit about what is this .eleventy.js file? This is our Eleventy config. So what's happening here?
00:10:43 - Ben Holmes
Yeah, this is the config that Eleventy specifically is going to look at, but we're also able to pick up on. You can think of Slinkity, if you want a visual, as the glue between Eleventy and the Vite bundler. Right now we're configuring just the Eleventy side over here, which is the base of our project and where all our data comes in. All we've done in this file is configure where our source directory is. Eleventy doesn't even have an opinion on where your source directory is — you have to tell it here. We've said "source" is going to be where our website lives. That's where our routes are. Slinkity is smart enough to look over there and say, okay, Eleventy wants "source" — we'll use "source" too.
00:11:21 - Anthony Campolo
Cool. That's what we're doing. Then we're also going to create a couple scripts here as well. We have "slinkity serve" and then just "slinkity" for the build. The serve one will start our Vite server and the build command will build our project into our "_site" folder. And if we wanted to deploy this to Netlify, that would be what we would do — use the build command. The start command we'll use in development. And we're not going to deploy this to production, because we're going to end up in a place where there are a couple of things we'll still have to deal with in terms of environment variables and things at a higher level. But this is going to be showing how do you just get the baseline thing connected to a database. Let's just spin this up here. Right now all we have going on is a simple index.md. So this is our Markdown index file that is going to be the entry point into our application. And we're going to run "yarn start" because we created that start command in our package.json.
00:12:29 - Anthony Campolo
And this will kick open our server on localhost. And there we go. So we just got our project going. Not much going on right now. We just have an H1 that says "StepZen Slinkity." So that's pretty nice. But this is where the interesting stuff comes in. Now we're going to actually get some JSX going. So we're going to have a JSX file with a basic little React component. It's a Hello component that's just returning a span. And the way we render that into our index page is going to be with this shortcode. So what is a shortcode?
00:13:14 - Ben Holmes
Yeah, a shortcode is just a function really, but it's a function that takes in a set of arguments. In this case, the name of our component — "hello" — and then it'll spit out some HTML for our page. And what's interesting is it's going to spit out HTML that renders a script tag, and that script tag is going to hydrate in our React component. It's a funky way to get JavaScript running on any templating language like Markdown, which we should see in a moment.
00:13:43 - Anthony Campolo
Yeah, so I want to just get these both on screen. So once I save this, then we will get an error. Oh, no. What happened?
00:13:54 - Ben Holmes
Well, you're committing heresy and putting your "hello" in a strange place.
00:13:59 - Anthony Campolo
Right. Because I skipped a step here. I was going to figure out how to do this without the includes folder, but we decided that that was actually a bad practice. We should not tell people to do that. Let's put this in an includes folder. What is the includes folder?
00:14:14 - Ben Holmes
Yes. So "includes" you can think of as like a junk drawer for everything that should not be a route on your site. If you've used a generic components folder in Next or something, this is that components folder. Then everything outside of includes is your pages. Because we don't want "hello" to be a route — we want it to be something we include somewhere else. We'll put it inside of includes. Right now we have a requirement to nest that inside of a components folder, but we're going to be dropping that very soon. That's all we've done here. Now we have it in components.
00:14:46 - Anthony Campolo
Yep. So I fixed that up. This is now in our includes folder and components folder. And then we modified our shortcode to tell it that our Hello component is inside of this components folder.
00:14:59 - Ben Holmes
Yep, that's it.
00:15:00 - Anthony Campolo
And hello to Alex Trost — Frontend Horse just popped in. Funny story, actually: me and Ben met through the Frontend Horse Discord and the React Podcast Discord. So Alex Trost deserves a little bit of credit for us getting this stream happening.
00:15:16 - Ben Holmes
I actually have my spooky whiteboard from just a moment ago. It's time to get spooky. Yeah, that's our name for the next couple of days, and then we've got to make it fall themed or something. I don't know. We need a Christmas name. We'll come up with one.
00:15:33 - Anthony Campolo
All right, so let's get some StepZen stuff going now. So I am really excited for this because what we're going to be doing here is we're going to be taking Slinkity, which is traditionally a Jamstack kind of framework. And most people who know what the Jamstack is, they think of it as a front end technology where you have a front end that is able to statically generate HTML, CSS, JavaScript and then put that on a CDN and load it up. But there's this new thing called Full Stack Jamstack. I'm the host of the Full Stack Jamstack podcast. This is something I'm very into and it involves taking these Jamstack frameworks and giving them backend power and capability. And the way we're going to be doing that is with StepZen. This is the StepZen stream. You know what StepZen is? Not quite sure how you found this, but happy to have you. We are going to be using a GraphQL API to serve up data through a GraphQL endpoint. And so the first thing we're going to do is we're going to create this index.graphql file, which is going to point to our other files.
00:16:38 - Anthony Campolo
And before we do anything complicated with databases or any of that, we just want to get a simple little test going on here. This is basically a test object that StepZen will generate mock JSON for us with this "getTest" query. And the way we're going to start up our server is with this "stepzen start" command. And then this is going to kick off a — let's see. Because it's already in the StepZen folder. And then we can run a little sample. Wait, where was my gist? I had a gist. This was the gist. Okay, then we can...
00:17:36 - Ben Holmes
When you go full stack, the browser tabs go flying.
00:17:39 - Anthony Campolo
I know, right? I always end up with like a million of these. So we're going to run a GraphQL query and it's going to do our "getTest" query and it's going to return a string. This is just a little mock JSON string right here. And we are on localhost 1000 — it's close enough.
00:17:57 - Ben Holmes
Close enough. It's a European language.
00:18:02 - Anthony Campolo
This is not actually running on localhost though. The endpoint itself — this is just our GraphiQL editor. If we see over here, we actually have a full deployed endpoint on pleasanton.stepzen.net. Now, if you create a StepZen account — if you go to stepzen.com, you can follow along with what we're doing here. You will get a deployed endpoint with a key that allows you to access it. So now that we have that set up, we're going to actually get this connected to our front end. And the way we're going to do that is by setting just a couple environment variables and then running a query through fetch. So let me just grab this whole chunk of code here and then we'll kind of talk about what's going on in it. We have a basic fetch request that's running through a useEffect. If you've ever done a fetch request to do a GraphQL query, it's actually pretty simple. All you have to do is just tell it that you're doing a POST request in the method, set the headers — which is going to be content type, application/JSON — set any headers that you need to set, and then send the query through the body by doing a JSON.stringify and then sending the query.
00:19:26 - Anthony Campolo
And then this is the actual query. Right now we're sending a "getTest" query and returning the string. Then we resolve the promise. Yeah, true. We need to get a Frontend Horse StepZen stream going.
00:19:44 - Ben Holmes
That'll be really fun. Just to break down what you just did — is it a dev server that's looking at GraphQL files and then generating endpoints from them, or generating queries from them?
00:19:59 - Anthony Campolo
Exactly. It generates the endpoints, not the queries. You create the schema. The schema has your types and has your queries, and it can also have your mutations if you're going to be writing as well. Right now we're just going to do some basic queries to read from the mock JSON. But later we're going to hook it up to a Supabase database to get access to dynamic data that we can generate, read, write, and do whatever we want to. But I've hopped off of sharing right now because now I need to put in my key. And this part's always a little bit tricky because you don't want to show your key on a stream, of course. And if you do that, then you end up looking quite silly — I've done it before.
00:20:51 - Ben Holmes
Yeah, we were talking earlier about environment variables on the front end. I don't know if you found anything there or if we're just not going to show that component anymore.
00:21:01 - Anthony Campolo
Yeah. So that's going to be a thing that — what I did is I basically added like 10 lines of white space and put the environment variables all the way at the bottom of the component, because it still reads it as if it's shipped. It's great. Yeah, this is the joys of live streaming — sometimes you've got to do some silly stuff to actually get it to work. But this is now good to go. So let me now start sharing again. Let me make sure I don't have anything sensitive showing. This is looking all good. So let's go — this, that, this, this, and that. So many windows. Oh my God. Okay, sure. Screen. Boom. Sweet. Okay, here we go. This is our whole component here. It is running now. We see that it is performing the GraphQL query. It is getting that same test string that we did before and it is displaying it on the page. And this is possible because of the magic of React and the magic of Slinkity to run that React. We have a useEffect. We have a useState. We run the useEffect hook and pass in the fetch state.
00:22:21 - Anthony Campolo
And then we use our useState to create a little "hello" variable and a "setHello" variable. You set "hello" with the response data — "getTest" string. And so this is pretty much your React data fetching 101 right now. There's a ton of stuff we're missing here, and this is just a proof of concept, showing the basic case of how do you do this. There's no loading — when I refresh, you see it's just blank up until we get the thing. So you'd want a loading state, you'd want an error state — kind of like a Redwood Cell. That would be a very useful thing to have. We don't quite have Cells yet in Slinkity. Maybe one day. But this is the very simplest way to run a fetch request, throw a GraphQL query over the wire, get a response back, stick it in your state, and render it on your page. That's pretty cool. It's very simple. It doesn't look super exciting, but having worked with a lot of pieces of tech like this, getting this to work is quite a lot of work.
00:23:24 - Anthony Campolo
And getting it all together with a nice framework — it's really impressive.
00:23:30 - Ben Holmes
Nice. Yeah. I'm sure you could expand this to use React Query or something, to abstract away the useEffect and just do a little magic there. I haven't used it much, I just know it's a nice GraphQL pairing.
00:23:43 - Anthony Campolo
Yeah, React Query would be a good thing to do. There are two different things you look at here, which is that if you're using React Query, there will still be the question of how you actually make the query. So you could use React Query with a fetch call, or you could use React Query with GraphQL Request. So if we brought in the GraphQL Request library, that would abstract away a little bit of this fetch call, and you wouldn't have to set the body and JSON.stringify it and all that.
00:24:13 - Ben Holmes
Yeah, yeah, that's the piece for sure.
00:24:15 - Anthony Campolo
Yeah, yeah. So there are a lot of different libraries we could bring in to simplify this and make it a little nicer. But for the sake of this stream, I thought it would be good to really just show that all you've got to do is a fetch request. If you want to get this to work, I think that is pretty cool.
00:24:32 - Ben Holmes
I will at least call out — I'm sure we don't have time to demo it, but if you wanted to do this fetch at build time, totally possible with Eleventy. If you make your own little Eleventy data file and make the request server side, you could throw that into your React component so that it immediately shows the result and you don't even need a loading spinner. It could be out of date because it's a build time process. Eleventy Serverless is coming, and that will help with that. But you can do it at any level of the full stack — that's the takeaway.
00:25:01 - Anthony Campolo
Yeah, Eleventy Serverless is going to be a crucial piece of this if we want to complete this, because that's where you would be able to hide your API key. Because I just did that whole song and dance hiding the API key. But the problem is right now our API key is in our front end — it's in our Hello.jsx file. So if we were to open up our source maps and look at the outputted bundle, you would see the key right in there. So we can't deploy this. We can't actually send this to production right now. So that's kind of the next thing to figure out after we get this project actually working. But that's something we're going to be figuring out as we get deeper into these Slinkity full stack projects. We'll have docs and conventions for dealing with environment variables and all that kind of stuff. But you all are getting a peek into the future right now.
00:25:54 - Ben Holmes
Yeah, when it comes to servers, it's mostly Eleventy doing the work too, where it's like, all we need to do is make sure that Vite is able to go to your serverless functions and process things correctly. It's easier than you might think. I'd definitely like to get there. But right now if you use plain Eleventy, you can just deploy a route on a serverless function by adding a little serverless front matter attribute, and that will throw it in a folder. You can use Netlify DPR and all that fanciness, or just AWS — that's what they support right now. With that you can get a nice full [unclear] experience where every page refresh will fetch the new query. We just need that to work with React. That's the next big thing.
00:26:35 - Anthony Campolo
Indeed. What I'm going to do now is I'm going to spin up a Supabase project. Have you ever used Supabase, Ben?
00:26:45 - Ben Holmes
The Jamstack Conf talk was hilarious, but no, I haven't used it.
00:26:49 - Anthony Campolo
It was. Yeah, the Jamstack Conf talk was very, very good. So for people who weren't there — there was a really great talk. Supabase is a database company. And this is the one — John Myers. Yeah, so he did a lightning launch for Supabase Functions, which are a way to run stored procedures in your Postgres database. There were all sorts of great memes and jokes in there. But for anyone who hasn't used it before, it's really great because it's literally just a Postgres database that is entirely yours to do whatever you want with. They spin up the database for you, they give you lots of nice conventions in terms of how to connect to it, they give you an API key, they give you an endpoint, and they actually give you fully RESTful APIs to hook into that database. And so that's going to be what we'll be showing here — we're going to take their Postgres endpoints. So PostgREST is a way to expose endpoints. Yeah, it's one of those things...
00:28:04 - Ben Holmes
Interesting.
00:28:06 - Anthony Campolo
PostgREST.
00:28:07 - Ben Holmes
Yeah. When you said it's something called "postgres," I was like, yeah, I've heard of that. No, it's this.
00:28:12 - Anthony Campolo
I am aware of Postgres. Yes. Yeah, PostgREST. And this is really great for StepZen because StepZen has a way to feed in a RESTful endpoint into your GraphQL schema. And we actually had Paul on not too long ago to show what we're doing here. You see, I've got my nice little StepZen blazer on there as well. This is a longer stream showing what we're doing here. We had to do a condensed version just to get this up and going with Slinkity. But if you're curious about the Supabase part and want to learn a little bit more about that, I would recommend checking this out — and I'll drop that link here for you all. It takes a little bit of time to get spun up, but now we're pretty much good to go. I'm also going to tear this down eventually — I'm exposing my keys, but that's not really an issue because it's just a simple little test database. Here, this is our StepZen config YAML file and this is where we set our API key. And so this is going to handle that for us. And then our config YAML is in our .gitignore so it doesn't actually get deployed.
00:29:32 - Anthony Campolo
And then we're going to have this thing right here. So this is going to be our actual query. The way we do that is we grab this URL here, which is the supabase.co URL, and feed that in. And we see how it has "/books" — that's because we're going to actually create a books table. And like most really nice modern database tools these days, they give you a really cool UI to just create some tables quickly. So we're going to create "books" and then we're going to add a column for "name," and that is going to be a text type. Save that. And then we're also going to insert some rows — one will just be "test," then "test two," then "spooky test." Gotta have the spookiness.
00:30:40 - Ben Holmes
That's terrifying.
00:30:42 - Anthony Campolo
I know, I'm so scared. Okay, and if we wanted to, I have some curl commands here that you could run to figure out whether it works or not. But we're going to skip right past that and just get right into the StepZen parts. I think our endpoint should be all set up correctly right now. So now we just need to run "stepzen start," and this is going to do everything for us. It'll take that key and slot it in with this "headers" thing here. And that's going through the Supabase config. Now if we just want to run this query, we should be able to get back our data — the "test," "test 2," and "spooky test."
00:31:25 - Ben Holmes
Very simple.
00:31:26 - Anthony Campolo
Yeah, yeah, yeah. Any questions about that? What just happened?
00:31:32 - Ben Holmes
Well, I mean, you made a database, it generates a localhost for you, and then you can query it. That's awesome. It's interesting that I can just wire up Postgres to a query. I don't know — how custom can you get with query resolvers and all of that?
00:31:50 - Anthony Campolo
That's the thing with StepZen — you are not writing resolvers at all. We actually give you a couple super powerful directives. You can even do things like say, I have two queries that I want to run and one query needs to receive the output of another query first as arguments. I can chain queries together and feed one into the other. Or if I wanted to create a relationship between two queries — say I want a foreign key that attaches to another query — you can do that as well with @materializer and different StepZen directives. We give you conventions for wiring all this up in almost any way you can think of. It's a very, very powerful system. Super cool. And I highly recommend everyone who is interested in this kind of stuff to check it out. I am going to hop off stream so that I can put some keys in. And this is where the magic happens. So this is why I was saying that this is a good example of what I call full stack Jamstack — because we haven't really deviated from the Jamstack part of this. We still have a static front end that is decoupled from our back end, which is really nice.
00:33:14 - Anthony Campolo
But we also now have a database — an entire database that we own. We have our own data. We don't need to use some third-party CMS. But at the same time, if we want to use a third-party CMS, we can do that as well because we can just hook into any endpoint you can think of. So I did another stream recently with the Storyblok people and they have a GraphQL endpoint, so right now we're feeding in a REST endpoint, but if you want to feed in a GraphQL endpoint, you could also do that and you're pretty much good to go there as well. So you have a ton of flexibility here in terms of what you're doing and how you get it all to work.
00:33:59 - Ben Holmes
Yeah. So I think you mentioned before that Supabase is very REST-y and StepZen loves being GraphQL-y. Is there any thought of Supabase using other protocols other than PostgREST, or is that kind of their North Star at the moment?
00:34:19 - Anthony Campolo
Yeah, I think at this point they're not really planning on doing anything else. They're probably just going to keep exposing that current thing rather than doing the whole — how do you figure out how to get PostGraphile involved? I don't think they're going to go that far with it. So this is why StepZen is pretty nice — it gives you everything you need to get set up with a GraphQL endpoint and then not really have to worry about how to do that translation. But I don't know, you'd have to probably ask Paul that. I'm almost there. Let me get this up and that up. Okay. And then let me just make sure I don't have any keys showing. All right, cool.
00:35:28 - Ben Holmes
There it is.
00:35:30 - Anthony Campolo
So now we have here on our front end, we are seeing the same response that we got earlier from our StepZen query. And then we're actually taking those results and putting them on the page. So now we have a Slinkity project that is connected to a Postgres database via Supabase, that is making a GraphQL query through StepZen to then translate that into a REST query that then gives you back the data. And so this is our whole full stack Jamstack Slinkity project.
00:36:04 - Ben Holmes
There it is. Yeah. This must be the 30th way to bring data back to the front end with Jamstack. But I think it's a cool number 30. Another horse in the race.
00:36:19 - Anthony Campolo
The thing I like about it is that I find that with most Jamstack technologies, they push you towards third-party CMSs and more built-out data solutions, which is great for lots of reasons. And if you're working with a team that has content editors who aren't necessarily technical — exactly, that's what it's really for. But if you're just a developer who wants to build a full stack application — and what's up, Chan? — and you just want to be able to say, hey, I want to have a Postgres database because Postgres is what I know how to use, then it's really great because you can have this whole full stack project with a database you know really well. And if we wanted to do this with a different Postgres database, we could also do that, although then we'd have to figure out the translation of the REST endpoint. It's also worth pointing out — sorry about that noise, I'm in the noisy city of Oakland — so if we check out our docs here, we actually have some docs showing how to connect to Supabase without using their REST connector.
00:37:34 - Anthony Campolo
There's another thing we have called "@dbquery." With @dbquery, you literally just —
00:37:40 - Ben Holmes
That's so funky.
00:37:43 - Anthony Campolo
Write an actual SQL query. If you wanted to say "SELECT * FROM books WHERE the date is greater than this," you can do that as well. So there are going to be a lot of different ways to do this. I find that doing the REST endpoint through the REST connector is a little bit more comprehensible to people than doing the whole @dbquery, because it's a little more of a specialized StepZen thing. But there are going to be lots of different ways to do it. I did another stream with the Railway team — not Supabase, Railway — and with that one, what we did is we took a Postgres database, ran it through PostGraphile, and then PostGraphile creates a GraphQL endpoint that you can feed into StepZen's @graphql directive. So it's almost comical the amount of ways you can figure out how to attach to a Postgres database with StepZen. You can do it through @dbquery, you can do it through @rest, or you can do it through @graphql. Whatever floats your boat.
00:38:51 - Anthony Campolo
Whatever suits your fancy is the way you could figure out how to do it. But the point is there's a ton of flexibility here and we really want to give developers options in how they're going to connect to their database. There's going to be something for everyone, I think, in terms of your mental model and where you're coming from. Do you already know GraphQL? Do you already know how to work with REST endpoints? Do you already know how to write SQL queries really well? Most people are going to be coming from a certain perspective in terms of what they know and what they're comfortable with. So I really like the fact that we give developers all of these options to do things however they want to do it.
00:39:36 - Ben Holmes
I agree. Yeah, I mean, the closest analogy that comes to mind is — it's kind of like how Gatsby exposes all of your data via GraphQL and you can decide how information gets into that GraphQL funnel. But StepZen is like, we're actually going to make some full stack endpoints that you can hit. But it's a similar philosophy of: bring your own — not even backend, just the back of the backend, the database, and how to connect to that database — and you can do anything you want from there. Which I think is pretty interesting.
00:40:07 - Anthony Campolo
Yeah, what you said there — I've seen —
00:40:08 - Ben Holmes
— before the stream. So yeah, similarities.
00:40:12 - Anthony Campolo
This is the usual thing when I bring people onto the stream. I'm like, you'll explain your part, I'll explain the StepZen part, and then we'll build the project together, and they'll be like, wow, I have no idea how that works, but it works.
00:40:24 - Ben Holmes
You can do that.
00:40:25 - Anthony Campolo
And you mentioned "back of the back end." So this is a popular phrasing that I'm hearing more and more. You have the front of the front end, which is HTML and CSS. Then you have the back of the front end, which is data fetching and Redux and how you actually do data management. And then you have the front of the back end — which I would say is StepZen. StepZen is like the front of the back end because it's a gateway into your backend architecture. And then the back of the back end is the actual database itself — what is the database, where is the database. And so we have this whole connection: front of the front end, back of the front end, front of the back end, back of the back end. And it gives you a way to separate the full stack into these different layers. And for me, this has been very, very useful. As someone who was trained in a quote unquote full stack bootcamp, we kind of went through a sequence like this, but it was never really made explicit. Like, we were never really told when we were at the front or the back of the front end.
00:41:26 - Ben Holmes
Oh, I know, right?
00:41:27 - Anthony Campolo
Crossing that barrier, you just kind of go through it and you're just like, ah, hopefully we'll get it by the time we hit the end of it. It's just like, halfway through you're like, nothing makes sense. And then by the time you get to the back of the back end, you're like, why didn't they start at the back of the back end? That would have made so much more sense, at least for me.
00:41:45 - Ben Holmes
Yeah, people go both ways. I'm definitely more like, I'll go from designs to front end to understand what the heck the data should be, and then model out how I want my front end to receive that, and then deal with the database later. That's my bias toward the front end for sure — where I don't want to touch databases. But I feel like it goes both ways. It's almost why GraphQL exists. Front end was frustrated with having so many different needs depending on the view, and they wanted a language that's like — backend, figure out what I want, here's a way that I can tell you exactly the shape of the thing I want — and then we can have this front of the back end, back of the back end split to take that database stuff and massage it into what the front end wants. So I could see it going both ways. But yeah, GraphQL is really opening that door of making front end easier.
00:42:37 - Anthony Campolo
Yeah. And then you mentioned Gatsby. So do you have much experience working with Gatsby?
00:42:41 - Ben Holmes
It's just the weird fish that came to mind — it's the only time I've seen GraphQL used to access what's honestly not even back-of-the-front-end data, because you do all your GraphQL queries at build time pretty much. But you're even using GraphQL to access your images. It's like, I'm used to just going to "assets/image.jpeg." Why am I writing a GraphQL query? That's because you want this layer in front that lets you communicate: here's what I actually need to ship to the end user, don't ship all my data please. Then reformatting it on the fly — like, I want to turn this image into a beautifully formatted image, or whatever else. And that lets you do the transformations as well. So my loose experience with Gatsby was: I used it for a personal site because I wanted ImageSharp. That's probably the reason everyone got into Gatsby — that image plugin is cool, and then the rest of it... Yeah, it's funny that that's the feature. That's why I got into it.
00:43:41 - Anthony Campolo
Yeah. My co-host Chris, who does the Full Stack Jamstack podcast with me, said the Gatsby image component was the specific reason he started using Gatsby. And for me, the GraphQL stuff is what always interested me about Gatsby. And what we built today is kind of a really rudimentary version of what you could do with something like Gatsby — because you get a GraphQL endpoint that can pull in data from almost anywhere and you can feed that into your front end. So this is kind of why I was really excited to do this project, because there aren't a lot of other projects that do this. But I think there's merit to it, and we need a better, more modern way of doing this. Because Gatsby is really great — I used Gatsby a lot back in the day — but I don't really use it so much today because I feel like it's accumulated a bit of legacy in terms of how it's developed, and the plugin ecosystem is kind of shaky. You never really know what plugins you're getting.
00:44:42 - Anthony Campolo
So I want to build out more greenfield examples of how to combine this GraphQL data fetching with a really nice front end static thing that also involves React and partial hydration and all that kind of stuff. So Slinkity to me seems like a really great project to do that with. And StepZen is a really great GraphQL tool to do that with. So this is like the very beginning of this integration. But I think this is something that's actually going to be very powerful. Once we get the environment variables and the serverless functions figured out, we're going to have a really cool full stack way to use Slinkity. Really glad you came onto the stream to do this with me. This is just the beginning, I think, of a lot of really cool, interesting work that we'll be doing over the next couple of months.
00:45:28 - Ben Holmes
I totally agree. Yeah, I mean, it's starting from the bare basics and slowly walking up features — like, now I want shared state between the little islands of components on my page, or I want serverless functions so every page refresh fetches it fresh. And then I think the final step is going to be this reckoning of single page apps versus multi page apps. Everyone's talking about it and it's going to be part of the Slinkity story. It's part of one of the initial features I worked on, actually, when I thought of Slinkity in the first place — like, what if you could tie together pages as a single page app, but choose which pages are part of that single page app marriage, where you can have little single page apps like islands, but on your website level? And everyone's kind of moving toward that. I know Rich Harris had that very interesting talk on what transitional apps mean — like, we don't want to commit to only multi page or only single page. We want to have the right amount of JavaScript at the right time, and everyone's going at it from a different angle.
00:46:30 - Ben Holmes
And whoever wins — I don't know, I think we'll end up with just a bunch of flavors and everyone chooses their favorite. That seems to be how things always go.
00:46:38 - Anthony Campolo
No one ever —
00:46:39 - Ben Holmes
We have more flavors than ever. No one has chosen the perfect stack. Like, Slinkity versus Astro especially — some people in the Eleventy community love using Vue templates, Nunjucks, and so on. And this approach works great for their existing stack. And then on the Astro side, it's like, I love using JSX already, this is the fit for me, I didn't want to use any Eleventy templates anyway. So it's like different flavors, but we're getting the same output for the end user, so who cares? Just use what you enjoy as long as it gives the end user what they need.
00:47:15 - Anthony Campolo
Yeah. It's worth pointing out that we are actually collaborating with the Astro team to start building out parts of Slinkity. When people look at these frameworks and think of framework competition or framework wars, I find that's almost never the case. When there are similar projects aiming for similar goals, there's actually not hostility and animosity — there's actually a greater need to collaborate, because it shows that almost no one else is working on this except us. So when you find someone else working on this, you're like, oh, cool, let's exchange notes actually.
00:47:50 - Ben Holmes
Yeah. I mean, it happens at the framework level too. Like, Svelte's inspired by React, and Vue is inspired by Svelte for Vue 3, at least. Looking at Vue 3, I'm like, this seems familiar to me. Like, everyone's looking at everyone else's homework in some way or another. And right now we're doing that to figure out — we only support React right now, let's support everyone. And then Astro is like, we have this renderer plugin set up to support everyone, probably port it to your setup. And so we'll see how that goes to just support everyone in the very same way. Because we're both islands architecture projects that are very bare bones, so it's easy to just use similar approaches.
00:48:30 - Anthony Campolo
Yep. So I'm going to drop a couple links here. Your Twitter is @bholmesdev if anyone wants to follow you or see what you're doing. We've also got slinkity.dev for anyone who's curious about learning more about Slinkity. We've of course got stepzen.com if you want to learn more about StepZen. And then I am @ajcwebdev on Twitter as well. So if you enjoyed this, if you want to learn more about this, feel free to contact either me or Ben. And then in the next coming weeks, we're going to have some example projects up on StepZen Samples with Slinkity and Supabase showing how to do this. It'll be a repo as well, if you want to clone this code down and start playing with it. So, really excited to get some more of this material out there into the world, and would really love to talk to anyone who's interested in doing any of this. And with that, is there anything else you'd like to say to our viewers before we close it out?
00:49:35 - Ben Holmes
Nothing. No. Go check out our contributing guide as well if you want to get involved in this sort of thing. We love having contributors. We're actually getting more contributors and bug reports than ever, which is great. See you over there, I guess.
00:49:52 - Anthony Campolo
Yeah, I will go ahead and pop that in there as well. Great. Well, thank you so much, everyone who was watching this. Really appreciate it.
00:49:59 - Ben Holmes
And —
00:49:59 - Anthony Campolo
And we will catch you next Friday, 12 PM Pacific time, like usual. Have a good day, everyone. Thanks.