main
tsx 376 lines 15.3 KB
Raw
1 import type { Metadata } from "next";
2 import Link from "next/link";
3 import { StructuredData } from "@/components/structured-data";
4 import { absoluteUrl, genPageMetadata } from "../seo";
5
6 const comparisonRows = [
7 {
8 label: "Deploy workflow",
9 smbcloud:
10 "Run `smb`, deploy over SSH, and watch the logs while it happens.",
11 heroku: "Managed platform workflow with its own conventions and habits.",
12 },
13 {
14 label: "Best fit",
15 smbcloud:
16 "Small teams that want a simple deploy flow and fewer moving parts.",
17 heroku:
18 "Teams already comfortable with Heroku and happy to keep working that way.",
19 },
20 {
21 label: "Runtime focus",
22 smbcloud: "Node.js, Ruby on Rails, and Swift/Vapor.",
23 heroku: "A broader app platform with a longer-established ecosystem.",
24 },
25 {
26 label: "Why teams pick it",
27 smbcloud: "Because it feels easier to follow and easier to operate.",
28 heroku: "Because it is familiar and already part of the team's workflow.",
29 },
30 ];
31
32 const smbcloudFits = [
33 "You want Heroku-like simplicity, but with less platform in the middle.",
34 "You mostly ship Node.js, Rails, or Vapor apps.",
35 "You do not want a big platform story around a straightforward deploy.",
36 "You want to understand what is happening when the app goes live.",
37 ];
38
39 const herokuStillFits = [
40 "Your team is already deep into Heroku and happy there.",
41 "You depend on Heroku-specific workflows or add-ons.",
42 "You are not looking to change the way you deploy right now.",
43 ];
44
45 const bestFor = [
46 "Small SaaS teams",
47 "Client projects that need a repeatable deploy path",
48 "Rails apps",
49 "Node.js services and dashboards",
50 "Vapor backends",
51 ];
52
53 const faqs = [
54 {
55 question: "Is smbCloud a Heroku replacement?",
56 answer:
57 "For some teams, yes. If you mostly ship Node.js, Rails, or Vapor apps and want a simpler SSH-first deploy flow, smbCloud can make more sense.",
58 },
59 {
60 question: "Who should switch from Heroku to smbCloud?",
61 answer:
62 "Teams that still want simplicity, but want less platform in the middle.",
63 },
64 {
65 question: "Is smbCloud trying to match every Heroku feature?",
66 answer: "No. That is not the point. smbCloud is narrower on purpose.",
67 },
68 ];
69
70 export const metadata: Metadata = {
71 ...genPageMetadata({
72 title: "Heroku alternative for small teams",
73 description:
74 "Looking for a Heroku alternative? smbCloud is an SSH-first deploy platform for small teams shipping Node.js, Ruby on Rails, and Swift/Vapor apps.",
75 path: "/heroku-alternative",
76 keywords: [
77 "Heroku alternative",
78 "Heroku replacement",
79 "SSH-first deploy platform",
80 "deploy Node.js app",
81 "deploy Ruby on Rails app",
82 "deploy Vapor app",
83 "small team hosting platform",
84 ],
85 }),
86 };
87
88 const structuredData = {
89 "@context": "https://schema.org",
90 "@graph": [
91 {
92 "@type": "WebPage",
93 "@id": absoluteUrl("/heroku-alternative#webpage"),
94 url: absoluteUrl("/heroku-alternative"),
95 name: "Heroku alternative for small teams",
96 description:
97 "Compare smbCloud and Heroku for small-team app deployment workflows.",
98 isPartOf: {
99 "@id": absoluteUrl("/#website"),
100 },
101 },
102 {
103 "@type": "BreadcrumbList",
104 itemListElement: [
105 {
106 "@type": "ListItem",
107 position: 1,
108 name: "Home",
109 item: absoluteUrl("/"),
110 },
111 {
112 "@type": "ListItem",
113 position: 2,
114 name: "Heroku alternative",
115 item: absoluteUrl("/heroku-alternative"),
116 },
117 ],
118 },
119 {
120 "@type": "FAQPage",
121 mainEntity: faqs.map((faq) => ({
122 "@type": "Question",
123 name: faq.question,
124 acceptedAnswer: {
125 "@type": "Answer",
126 text: faq.answer,
127 },
128 })),
129 },
130 ],
131 };
132
133 export default function HerokuAlternativePage() {
134 return (
135 <div>
136 <StructuredData data={structuredData} />
137
138 <section className="relative overflow-hidden px-6 pt-24 pb-16 sm:pt-32 sm:pb-20 lg:px-8">
139 <div className="pointer-events-none absolute inset-x-0 top-0 -z-10 h-[520px] bg-[radial-gradient(ellipse_75%_50%_at_50%_0%,rgba(99,102,241,0.18),transparent)] dark:bg-[radial-gradient(ellipse_75%_50%_at_50%_0%,rgba(99,102,241,0.12),transparent)]" />
140
141 <div className="mx-auto max-w-4xl">
142 <div className="mb-6 inline-flex items-center gap-2 rounded-full border border-indigo-200 bg-indigo-50 px-4 py-1.5 dark:border-indigo-500/30 dark:bg-indigo-500/10">
143 <span className="h-1.5 w-1.5 rounded-full bg-indigo-500" />
144 <span className="text-xs font-semibold uppercase tracking-widest text-indigo-700 dark:text-indigo-400">
145 Heroku alternative
146 </span>
147 </div>
148
149 <h1 className="max-w-3xl text-4xl font-bold tracking-tight text-slate-900 dark:text-white sm:text-6xl leading-[1.05]">
150 Looking for a Heroku alternative?
151 </h1>
152
153 <p className="mt-6 max-w-3xl text-lg leading-8 text-slate-600 dark:text-slate-400">
154 We built smbCloud for teams that liked what Heroku got right but got
155 tired of how much platform ended up sitting between the code and the
156 deploy. SSH-first, one command, easy to follow.
157 </p>
158
159 <div className="mt-8 flex flex-col gap-4 sm:flex-row">
160 <Link
161 href="https://console.smbcloud.xyz"
162 target="_blank"
163 rel="noopener noreferrer"
164 className="inline-flex items-center justify-center rounded-lg bg-indigo-600 px-8 py-3.5 text-sm font-semibold text-white shadow-lg shadow-indigo-500/20 transition-all hover:bg-indigo-500 hover:shadow-indigo-500/30 active:scale-[0.98]"
165 >
166 Try smbCloud
167 </Link>
168 <Link
169 href="/posts/cli"
170 className="inline-flex items-center justify-center rounded-lg border border-slate-300 px-8 py-3.5 text-sm font-semibold text-slate-700 transition-colors hover:bg-slate-50 dark:border-white/[0.12] dark:text-slate-200 dark:hover:bg-white/[0.04]"
171 >
172 Install the CLI
173 </Link>
174 </div>
175 </div>
176 </section>
177
178 <section className="px-6 pb-24 lg:px-8">
179 <div className="mx-auto max-w-5xl grid gap-8 lg:grid-cols-[0.95fr_1.05fr]">
180 <div>
181 <p className="text-xs font-bold uppercase tracking-[0.2em] text-slate-400 dark:text-slate-600">
182 Why people leave Heroku
183 </p>
184 <h2 className="mt-4 text-3xl font-bold tracking-tight text-slate-900 dark:text-white">
185 Usually they still want simplicity. They just want less platform
186 around it.
187 </h2>
188 <p className="mt-5 text-base leading-8 text-slate-600 dark:text-slate-400">
189 That is basically the whole argument. Heroku got a lot right. I
190 just think a lot of teams eventually want something they can
191 explain in plain English.
192 </p>
193 </div>
194
195 <div className="rounded-2xl border border-slate-200 bg-slate-50 p-8 dark:border-white/[0.06] dark:bg-white/[0.02]">
196 <p className="text-sm font-semibold text-slate-900 dark:text-white">
197 What smbCloud does well
198 </p>
199 <ul className="mt-5 space-y-4 text-sm leading-7 text-slate-600 dark:text-slate-400">
200 <li className="flex gap-3">
201 <span className="mt-2 h-1.5 w-1.5 shrink-0 rounded-full bg-indigo-500" />
202 <span>Deploy over SSH with one command.</span>
203 </li>
204 <li className="flex gap-3">
205 <span className="mt-2 h-1.5 w-1.5 shrink-0 rounded-full bg-indigo-500" />
206 <span>Support for Node.js, Rails, and Swift/Vapor.</span>
207 </li>
208 <li className="flex gap-3">
209 <span className="mt-2 h-1.5 w-1.5 shrink-0 rounded-full bg-indigo-500" />
210 <span>A setup that feels closer to normal app operations.</span>
211 </li>
212 </ul>
213 </div>
214 </div>
215 </section>
216
217 <section className="border-t border-slate-200 px-6 py-24 dark:border-white/[0.06] lg:px-8">
218 <div className="mx-auto max-w-5xl">
219 <div className="mb-12 max-w-3xl">
220 <p className="text-xs font-bold uppercase tracking-[0.2em] text-slate-400 dark:text-slate-600">
221 smbCloud vs Heroku
222 </p>
223 <h2 className="mt-4 text-3xl font-bold tracking-tight text-slate-900 dark:text-white">
224 Here is the trade, without the usual sales fog.
225 </h2>
226 </div>
227
228 <div className="overflow-hidden rounded-2xl border border-slate-200 dark:border-white/[0.06]">
229 <div className="grid grid-cols-[0.8fr_1fr_1fr] bg-slate-50 text-sm font-semibold text-slate-900 dark:bg-white/[0.03] dark:text-white">
230 <div className="border-b border-slate-200 px-5 py-4 dark:border-white/[0.06]">
231 Area
232 </div>
233 <div className="border-b border-l border-slate-200 px-5 py-4 dark:border-white/[0.06]">
234 smbCloud
235 </div>
236 <div className="border-b border-l border-slate-200 px-5 py-4 dark:border-white/[0.06]">
237 Heroku
238 </div>
239 </div>
240 {comparisonRows.map((row) => (
241 <div
242 key={row.label}
243 className="grid grid-cols-[0.8fr_1fr_1fr] text-sm leading-7 text-slate-600 dark:text-slate-400"
244 >
245 <div className="border-b border-slate-200 bg-white px-5 py-5 font-semibold text-slate-900 dark:border-white/[0.06] dark:bg-white/[0.02] dark:text-white">
246 {row.label}
247 </div>
248 <div className="border-b border-l border-slate-200 bg-white px-5 py-5 dark:border-white/[0.06] dark:bg-white/[0.02]">
249 {row.smbcloud}
250 </div>
251 <div className="border-b border-l border-slate-200 bg-white px-5 py-5 dark:border-white/[0.06] dark:bg-white/[0.02]">
252 {row.heroku}
253 </div>
254 </div>
255 ))}
256 </div>
257 </div>
258 </section>
259
260 <section className="px-6 py-24 lg:px-8">
261 <div className="mx-auto grid max-w-5xl gap-6 lg:grid-cols-2">
262 <div className="rounded-2xl border border-slate-200 bg-white p-8 dark:border-white/[0.06] dark:bg-white/[0.02]">
263 <p className="text-xs font-bold uppercase tracking-[0.2em] text-slate-400 dark:text-slate-600">
264 Pick smbCloud if
265 </p>
266 <ul className="mt-6 space-y-4 text-sm leading-7 text-slate-600 dark:text-slate-400">
267 {smbcloudFits.map((item) => (
268 <li key={item} className="flex gap-3">
269 <span className="mt-2 h-1.5 w-1.5 shrink-0 rounded-full bg-indigo-500" />
270 <span>{item}</span>
271 </li>
272 ))}
273 </ul>
274 </div>
275
276 <div className="rounded-2xl border border-slate-200 bg-slate-50 p-8 dark:border-white/[0.06] dark:bg-white/[0.02]">
277 <p className="text-xs font-bold uppercase tracking-[0.2em] text-slate-400 dark:text-slate-600">
278 Stay on Heroku if
279 </p>
280 <ul className="mt-6 space-y-4 text-sm leading-7 text-slate-600 dark:text-slate-400">
281 {herokuStillFits.map((item) => (
282 <li key={item} className="flex gap-3">
283 <span className="mt-2 h-1.5 w-1.5 shrink-0 rounded-full bg-slate-400" />
284 <span>{item}</span>
285 </li>
286 ))}
287 </ul>
288 </div>
289 </div>
290 </section>
291
292 <section className="border-t border-slate-200 px-6 py-24 dark:border-white/[0.06] lg:px-8">
293 <div className="mx-auto max-w-5xl grid gap-8 lg:grid-cols-[0.95fr_1.05fr]">
294 <div>
295 <p className="text-xs font-bold uppercase tracking-[0.2em] text-slate-400 dark:text-slate-600">
296 Best fit
297 </p>
298 <h2 className="mt-4 text-3xl font-bold tracking-tight text-slate-900 dark:text-white">
299 I would look at smbCloud if you still want ease, just with less
300 ceremony.
301 </h2>
302 </div>
303 <ul className="rounded-2xl border border-slate-200 bg-white p-8 text-sm leading-7 text-slate-600 dark:border-white/[0.06] dark:bg-white/[0.02] dark:text-slate-400">
304 {bestFor.map((item) => (
305 <li
306 key={item}
307 className="flex gap-3 border-b border-slate-200 py-3 last:border-0 last:pb-0 first:pt-0 dark:border-white/[0.06]"
308 >
309 <span className="mt-2 h-1.5 w-1.5 shrink-0 rounded-full bg-indigo-500" />
310 <span>{item}</span>
311 </li>
312 ))}
313 </ul>
314 </div>
315 </section>
316
317 <section className="px-6 pb-24 lg:px-8">
318 <div className="mx-auto max-w-3xl">
319 <div className="mb-10">
320 <p className="text-xs font-bold uppercase tracking-[0.2em] text-slate-400 dark:text-slate-600">
321 FAQ
322 </p>
323 <h2 className="mt-4 text-3xl font-bold tracking-tight text-slate-900 dark:text-white">
324 Common questions
325 </h2>
326 </div>
327 <div className="space-y-4">
328 {faqs.map((faq) => (
329 <div
330 key={faq.question}
331 className="rounded-2xl border border-slate-200 bg-white p-6 dark:border-white/[0.06] dark:bg-white/[0.02]"
332 >
333 <h3 className="text-lg font-semibold text-slate-900 dark:text-white">
334 {faq.question}
335 </h3>
336 <p className="mt-3 text-sm leading-7 text-slate-600 dark:text-slate-400">
337 {faq.answer}
338 </p>
339 </div>
340 ))}
341 </div>
342 </div>
343 </section>
344
345 <section className="px-6 pb-20 lg:px-8">
346 <div className="mx-auto max-w-3xl">
347 <div className="relative overflow-hidden rounded-2xl bg-indigo-600 px-8 py-14 text-center shadow-2xl shadow-indigo-500/20">
348 <div className="pointer-events-none absolute inset-0 bg-[radial-gradient(ellipse_at_top,rgba(255,255,255,0.1),transparent)]" />
349 <h2 className="relative text-3xl font-bold tracking-tight text-white">
350 If Heroku feels like more platform than you need, try smbCloud.
351 </h2>
352 <p className="relative mt-4 text-indigo-200">
353 Run it on one app. That is usually enough to know.
354 </p>
355 <div className="relative mt-8 flex flex-col items-center justify-center gap-3 sm:flex-row">
356 <Link
357 href="https://console.smbcloud.xyz"
358 target="_blank"
359 rel="noopener noreferrer"
360 className="inline-flex rounded-lg bg-white px-8 py-3.5 text-sm font-semibold text-indigo-700 shadow-sm transition-colors hover:bg-indigo-50"
361 >
362 Start with smbCloud
363 </Link>
364 <Link
365 href="/railway-alternative"
366 className="inline-flex rounded-lg border border-white/20 px-8 py-3.5 text-sm font-semibold text-white transition-colors hover:bg-white/10"
367 >
368 Compare Railway alternative
369 </Link>
370 </div>
371 </div>
372 </div>
373 </section>
374 </div>
375 );
376 }