mycontext-cli 2.0.29 → 2.0.30

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,851 @@
1
+ ---
2
+ id: instantdb-integration
3
+ title: InstantDB Integration
4
+ description: Complete InstantDB setup with real-time database, authentication, and React integration
5
+ category: database
6
+ tags: ["instantdb", "realtime", "auth", "react", "nextjs"]
7
+ author: MyContext
8
+ version: 2.0.0
9
+ createdAt: 2025-10-09T10:00:00.000Z
10
+ updatedAt: 2025-10-10T23:30:00.000Z
11
+ difficulty: beginner
12
+ estimatedTime: "5 minutes (automatic) or 2-3 hours (manual)"
13
+ prerequisites: ["Node.js 18+"]
14
+ relatedPlaybooks: ["nextjs-auth", "react-forms", "state-management"]
15
+ ---
16
+
17
+ # InstantDB Integration Guide
18
+
19
+ > ⚡ **Quick Start:** MyContext CLI now handles this automatically! Run:
20
+ > ```bash
21
+ > mycontext init my-app --framework instantdb
22
+ > ```
23
+ > This guide is for manual setup or understanding what MyContext does under the hood.
24
+
25
+ Complete setup for InstantDB real-time database with authentication, schema management, and React integration for Next.js applications.
26
+
27
+ ## Overview
28
+
29
+ InstantDB provides a real-time database with built-in authentication, making it perfect for modern web applications. This guide covers:
30
+
31
+ - Database schema design and management
32
+ - Magic code authentication flow
33
+ - Real-time data synchronization
34
+ - React hooks and components
35
+ - CRUD operations with TypeScript
36
+ - File storage integration
37
+
38
+ ## Prerequisites
39
+
40
+ - Next.js 13+ project with App Router
41
+ - MyContext context files (PRD, types, brand)
42
+ - Node.js 18 or higher
43
+ - InstantDB account (free tier available)
44
+
45
+ ## Step 1: Installation and Setup
46
+
47
+ ### Install Dependencies
48
+
49
+ ```bash
50
+ # Install InstantDB packages
51
+ pnpm add @instantdb/react @instantdb/admin
52
+
53
+ # Install additional UI dependencies
54
+ pnpm add sonner # for toast notifications
55
+ ```
56
+
57
+ ### Environment Configuration
58
+
59
+ Create `.env.local`:
60
+
61
+ ```env
62
+ NEXT_PUBLIC_INSTANT_APP_ID=your_app_id_here
63
+ ```
64
+
65
+ ## Step 2: Schema Design
66
+
67
+ ### Create Schema File
68
+
69
+ Create `instant.schema.ts`:
70
+
71
+ ```typescript
72
+ import { i } from "@instantdb/react";
73
+
74
+ const schema = i.schema({
75
+ entities: {
76
+ // User entities (InstantDB built-in)
77
+ $users: i.entity({
78
+ email: i.string().unique().indexed(),
79
+ name: i.string(),
80
+ createdAt: i.date(),
81
+ updatedAt: i.date(),
82
+ }),
83
+
84
+ // Custom entities based on your project
85
+ profiles: i.entity({
86
+ userId: i.string(),
87
+ nickname: i.string(),
88
+ bio: i.string().optional(),
89
+ avatar: i.string().optional(),
90
+ preferences: i.json().optional(),
91
+ createdAt: i.date(),
92
+ updatedAt: i.date(),
93
+ }),
94
+
95
+ posts: i.entity({
96
+ title: i.string(),
97
+ content: i.string(),
98
+ authorId: i.string(),
99
+ published: i.boolean(),
100
+ tags: i.json().optional(),
101
+ createdAt: i.date(),
102
+ updatedAt: i.date(),
103
+ }),
104
+
105
+ comments: i.entity({
106
+ postId: i.string(),
107
+ authorId: i.string(),
108
+ content: i.string(),
109
+ parentId: i.string().optional(),
110
+ createdAt: i.date(),
111
+ updatedAt: i.date(),
112
+ }),
113
+ },
114
+
115
+ links: {
116
+ // User to profile relationship
117
+ userProfile: {
118
+ forward: { on: "profiles", has: "one", label: "user" },
119
+ reverse: { on: "$users", has: "one", label: "profile" },
120
+ },
121
+
122
+ // Post to author relationship
123
+ postAuthor: {
124
+ forward: { on: "posts", has: "one", label: "author" },
125
+ reverse: { on: "$users", has: "many", label: "posts" },
126
+ },
127
+
128
+ // Post to comments relationship
129
+ postComments: {
130
+ forward: { on: "comments", has: "many", label: "post" },
131
+ reverse: { on: "posts", has: "many", label: "comments" },
132
+ },
133
+
134
+ // Comment to author relationship
135
+ commentAuthor: {
136
+ forward: { on: "comments", has: "one", label: "author" },
137
+ reverse: { on: "$users", has: "many", label: "comments" },
138
+ },
139
+ },
140
+ });
141
+
142
+ export default schema;
143
+ ```
144
+
145
+ ## Step 3: Database Client Setup
146
+
147
+ ### Create Database Client
148
+
149
+ Create `lib/instantdb.ts`:
150
+
151
+ ```typescript
152
+ import { init, id } from "@instantdb/react";
153
+ import schema from "../instant.schema";
154
+
155
+ const db = init({
156
+ appId: process.env.NEXT_PUBLIC_INSTANT_APP_ID || "__APP_ID__",
157
+ schema,
158
+ });
159
+
160
+ export { db, id };
161
+
162
+ // Auth utilities
163
+ export const authUtils = {
164
+ async sendMagicCode(email: string) {
165
+ try {
166
+ await db.auth.sendMagicCode({ email });
167
+ return { success: true };
168
+ } catch (error) {
169
+ return { success: false, error: error.message };
170
+ }
171
+ },
172
+
173
+ async signInWithMagicCode(email: string, code: string) {
174
+ try {
175
+ await db.auth.signInWithMagicCode({ email, code });
176
+ return { success: true };
177
+ } catch (error) {
178
+ return { success: false, error: error.message };
179
+ }
180
+ },
181
+
182
+ async signOut() {
183
+ try {
184
+ await db.auth.signOut();
185
+ return { success: true };
186
+ } catch (error) {
187
+ return { success: false, error: error.message };
188
+ }
189
+ },
190
+ };
191
+
192
+ // Generic CRUD operations
193
+ export const dbUtils = {
194
+ async create(collection: string, data: any) {
195
+ try {
196
+ await db.transact([
197
+ db.tx[collection][id()].create({
198
+ ...data,
199
+ createdAt: Date.now(),
200
+ updatedAt: Date.now(),
201
+ }),
202
+ ]);
203
+ return { success: true };
204
+ } catch (error) {
205
+ return { success: false, error: error.message };
206
+ }
207
+ },
208
+
209
+ async update(collection: string, id: string, data: any) {
210
+ try {
211
+ await db.transact([
212
+ db.tx[collection][id].update({
213
+ ...data,
214
+ updatedAt: Date.now(),
215
+ }),
216
+ ]);
217
+ return { success: true };
218
+ } catch (error) {
219
+ return { success: false, error: error.message };
220
+ }
221
+ },
222
+
223
+ async delete(collection: string, id: string) {
224
+ try {
225
+ await db.transact([db.tx[collection][id].delete()]);
226
+ return { success: true };
227
+ } catch (error) {
228
+ return { success: false, error: error.message };
229
+ }
230
+ },
231
+ };
232
+
233
+ // Real-time hooks
234
+ export const useRealtimeQuery = (query: any) => {
235
+ return db.useQuery(query);
236
+ };
237
+
238
+ export const useUser = () => {
239
+ return db.useUser();
240
+ };
241
+ ```
242
+
243
+ ## Step 4: Authentication Components
244
+
245
+ ### Magic Code Login Form
246
+
247
+ Create `components/auth/LoginForm.tsx`:
248
+
249
+ ```typescript
250
+ "use client";
251
+
252
+ import { useState } from "react";
253
+ import { Button } from "@/components/ui/button";
254
+ import { Input } from "@/components/ui/input";
255
+ import {
256
+ Card,
257
+ CardContent,
258
+ CardDescription,
259
+ CardHeader,
260
+ CardTitle,
261
+ } from "@/components/ui/card";
262
+ import { authUtils } from "@/lib/instantdb";
263
+ import { toast } from "sonner";
264
+
265
+ interface LoginFormProps {
266
+ onSuccess?: () => void;
267
+ }
268
+
269
+ export function LoginForm({ onSuccess }: LoginFormProps) {
270
+ const [email, setEmail] = useState("");
271
+ const [code, setCode] = useState("");
272
+ const [step, setStep] = useState<"email" | "code">("email");
273
+ const [loading, setLoading] = useState(false);
274
+
275
+ const handleSendCode = async (e: React.FormEvent) => {
276
+ e.preventDefault();
277
+ if (!email) return;
278
+
279
+ setLoading(true);
280
+ const result = await authUtils.sendMagicCode(email);
281
+ setLoading(false);
282
+
283
+ if (result.success) {
284
+ setStep("code");
285
+ toast.success("Magic code sent to your email!");
286
+ } else {
287
+ toast.error(result.error || "Failed to send code");
288
+ }
289
+ };
290
+
291
+ const handleVerifyCode = async (e: React.FormEvent) => {
292
+ e.preventDefault();
293
+ if (!code) return;
294
+
295
+ setLoading(true);
296
+ const result = await authUtils.signInWithMagicCode(email, code);
297
+ setLoading(false);
298
+
299
+ if (result.success) {
300
+ toast.success("Successfully signed in!");
301
+ onSuccess?.();
302
+ } else {
303
+ toast.error(result.error || "Invalid code");
304
+ }
305
+ };
306
+
307
+ return (
308
+ <Card className="w-full max-w-md mx-auto">
309
+ <CardHeader>
310
+ <CardTitle>Sign In</CardTitle>
311
+ <CardDescription>
312
+ {step === "email"
313
+ ? "Enter your email to receive a magic code"
314
+ : "Enter the code sent to your email"}
315
+ </CardDescription>
316
+ </CardHeader>
317
+ <CardContent>
318
+ {step === "email" ? (
319
+ <form onSubmit={handleSendCode} className="space-y-4">
320
+ <Input
321
+ type="email"
322
+ placeholder="Enter your email"
323
+ value={email}
324
+ onChange={(e) => setEmail(e.target.value)}
325
+ required
326
+ />
327
+ <Button type="submit" className="w-full" disabled={loading}>
328
+ {loading ? "Sending..." : "Send Magic Code"}
329
+ </Button>
330
+ </form>
331
+ ) : (
332
+ <form onSubmit={handleVerifyCode} className="space-y-4">
333
+ <Input
334
+ type="text"
335
+ placeholder="Enter magic code"
336
+ value={code}
337
+ onChange={(e) => setCode(e.target.value)}
338
+ required
339
+ />
340
+ <div className="flex gap-2">
341
+ <Button
342
+ type="button"
343
+ variant="outline"
344
+ onClick={() => setStep("email")}
345
+ className="flex-1"
346
+ >
347
+ Back
348
+ </Button>
349
+ <Button type="submit" className="flex-1" disabled={loading}>
350
+ {loading ? "Verifying..." : "Verify Code"}
351
+ </Button>
352
+ </div>
353
+ </form>
354
+ )}
355
+ </CardContent>
356
+ </Card>
357
+ );
358
+ }
359
+ ```
360
+
361
+ ### User Dashboard
362
+
363
+ Create `components/auth/UserDashboard.tsx`:
364
+
365
+ ```typescript
366
+ "use client";
367
+
368
+ import { db } from "@/lib/instantdb";
369
+ import { Button } from "@/components/ui/button";
370
+ import {
371
+ Card,
372
+ CardContent,
373
+ CardDescription,
374
+ CardHeader,
375
+ CardTitle,
376
+ } from "@/components/ui/card";
377
+ import { authUtils } from "@/lib/instantdb";
378
+ import { toast } from "sonner";
379
+
380
+ export function UserDashboard() {
381
+ const user = db.useUser();
382
+
383
+ const handleSignOut = async () => {
384
+ const result = await authUtils.signOut();
385
+ if (result.success) {
386
+ toast.success("Signed out successfully");
387
+ } else {
388
+ toast.error(result.error || "Failed to sign out");
389
+ }
390
+ };
391
+
392
+ if (!user) {
393
+ return null;
394
+ }
395
+
396
+ return (
397
+ <Card className="w-full max-w-md mx-auto">
398
+ <CardHeader>
399
+ <CardTitle>Welcome, {user.email}!</CardTitle>
400
+ <CardDescription>Your account dashboard</CardDescription>
401
+ </CardHeader>
402
+ <CardContent className="space-y-4">
403
+ <div>
404
+ <p className="text-sm text-muted-foreground">Email:</p>
405
+ <p className="font-medium">{user.email}</p>
406
+ </div>
407
+ <div>
408
+ <p className="text-sm text-muted-foreground">User ID:</p>
409
+ <p className="font-mono text-xs">{user.id}</p>
410
+ </div>
411
+ <Button onClick={handleSignOut} variant="outline" className="w-full">
412
+ Sign Out
413
+ </Button>
414
+ </CardContent>
415
+ </Card>
416
+ );
417
+ }
418
+ ```
419
+
420
+ ### Auth Provider
421
+
422
+ Create `components/auth/AuthProvider.tsx`:
423
+
424
+ ```typescript
425
+ "use client";
426
+
427
+ import { db } from "@/lib/instantdb";
428
+ import { LoginForm } from "./LoginForm";
429
+ import { UserDashboard } from "./UserDashboard";
430
+
431
+ export function AuthProvider() {
432
+ return (
433
+ <db.SignedIn>
434
+ <UserDashboard />
435
+ </db.SignedIn>
436
+ );
437
+ }
438
+
439
+ export function AuthForm() {
440
+ return (
441
+ <db.SignedOut>
442
+ <LoginForm />
443
+ </db.SignedOut>
444
+ );
445
+ }
446
+ ```
447
+
448
+ ## Step 5: Real-time Data Components
449
+
450
+ ### Posts List with Real-time Updates
451
+
452
+ Create `components/posts/PostsList.tsx`:
453
+
454
+ ```typescript
455
+ "use client";
456
+
457
+ import { useRealtimeQuery, dbUtils } from "@/lib/instantdb";
458
+ import { Button } from "@/components/ui/button";
459
+ import {
460
+ Card,
461
+ CardContent,
462
+ CardDescription,
463
+ CardHeader,
464
+ CardTitle,
465
+ } from "@/components/ui/card";
466
+ import { toast } from "sonner";
467
+
468
+ export function PostsList() {
469
+ const { data, isLoading, error } = useRealtimeQuery({
470
+ posts: {
471
+ author: {},
472
+ },
473
+ });
474
+
475
+ const handleDeletePost = async (postId: string) => {
476
+ const result = await dbUtils.delete("posts", postId);
477
+ if (result.success) {
478
+ toast.success("Post deleted");
479
+ } else {
480
+ toast.error("Failed to delete post");
481
+ }
482
+ };
483
+
484
+ if (isLoading) return <div>Loading posts...</div>;
485
+ if (error) return <div>Error loading posts: {error.message}</div>;
486
+
487
+ const posts = data?.posts || [];
488
+
489
+ return (
490
+ <div className="space-y-4">
491
+ <h2 className="text-2xl font-bold">Posts</h2>
492
+ {posts.length === 0 ? (
493
+ <p className="text-muted-foreground">No posts yet</p>
494
+ ) : (
495
+ posts.map((post: any) => (
496
+ <Card key={post.id}>
497
+ <CardHeader>
498
+ <CardTitle>{post.title}</CardTitle>
499
+ <CardDescription>
500
+ By {post.author?.email || "Unknown"} •{" "}
501
+ {new Date(post.createdAt).toLocaleDateString()}
502
+ </CardDescription>
503
+ </CardHeader>
504
+ <CardContent>
505
+ <p className="text-sm">{post.content}</p>
506
+ <div className="mt-4 flex gap-2">
507
+ <Button
508
+ variant="destructive"
509
+ size="sm"
510
+ onClick={() => handleDeletePost(post.id)}
511
+ >
512
+ Delete
513
+ </Button>
514
+ </div>
515
+ </CardContent>
516
+ </Card>
517
+ ))
518
+ )}
519
+ </div>
520
+ );
521
+ }
522
+ ```
523
+
524
+ ### Create Post Form
525
+
526
+ Create `components/posts/CreatePostForm.tsx`:
527
+
528
+ ```typescript
529
+ "use client";
530
+
531
+ import { useState } from "react";
532
+ import { useUser, dbUtils } from "@/lib/instantdb";
533
+ import { Button } from "@/components/ui/button";
534
+ import { Input } from "@/components/ui/input";
535
+ import { Textarea } from "@/components/ui/textarea";
536
+ import {
537
+ Card,
538
+ CardContent,
539
+ CardDescription,
540
+ CardHeader,
541
+ CardTitle,
542
+ } from "@/components/ui/card";
543
+ import { toast } from "sonner";
544
+
545
+ export function CreatePostForm() {
546
+ const user = useUser();
547
+ const [title, setTitle] = useState("");
548
+ const [content, setContent] = useState("");
549
+ const [loading, setLoading] = useState(false);
550
+
551
+ const handleSubmit = async (e: React.FormEvent) => {
552
+ e.preventDefault();
553
+ if (!user || !title || !content) return;
554
+
555
+ setLoading(true);
556
+ const result = await dbUtils.create("posts", {
557
+ title,
558
+ content,
559
+ authorId: user.id,
560
+ published: true,
561
+ });
562
+ setLoading(false);
563
+
564
+ if (result.success) {
565
+ toast.success("Post created successfully!");
566
+ setTitle("");
567
+ setContent("");
568
+ } else {
569
+ toast.error("Failed to create post");
570
+ }
571
+ };
572
+
573
+ if (!user) {
574
+ return (
575
+ <Card>
576
+ <CardContent className="pt-6">
577
+ <p className="text-muted-foreground">
578
+ Please sign in to create posts
579
+ </p>
580
+ </CardContent>
581
+ </Card>
582
+ );
583
+ }
584
+
585
+ return (
586
+ <Card>
587
+ <CardHeader>
588
+ <CardTitle>Create New Post</CardTitle>
589
+ <CardDescription>
590
+ Share your thoughts with the community
591
+ </CardDescription>
592
+ </CardHeader>
593
+ <CardContent>
594
+ <form onSubmit={handleSubmit} className="space-y-4">
595
+ <Input
596
+ placeholder="Post title"
597
+ value={title}
598
+ onChange={(e) => setTitle(e.target.value)}
599
+ required
600
+ />
601
+ <Textarea
602
+ placeholder="What's on your mind?"
603
+ value={content}
604
+ onChange={(e) => setContent(e.target.value)}
605
+ rows={4}
606
+ required
607
+ />
608
+ <Button type="submit" disabled={loading} className="w-full">
609
+ {loading ? "Creating..." : "Create Post"}
610
+ </Button>
611
+ </form>
612
+ </CardContent>
613
+ </Card>
614
+ );
615
+ }
616
+ ```
617
+
618
+ ## Step 6: File Storage Integration
619
+
620
+ ### File Upload Component
621
+
622
+ Create `components/storage/FileUpload.tsx`:
623
+
624
+ ```typescript
625
+ "use client";
626
+
627
+ import { useState } from "react";
628
+ import { db } from "@/lib/instantdb";
629
+ import { Button } from "@/components/ui/button";
630
+ import {
631
+ Card,
632
+ CardContent,
633
+ CardDescription,
634
+ CardHeader,
635
+ CardTitle,
636
+ } from "@/components/ui/card";
637
+ import { toast } from "sonner";
638
+
639
+ export function FileUpload() {
640
+ const [file, setFile] = useState<File | null>(null);
641
+ const [uploading, setUploading] = useState(false);
642
+
643
+ const handleFileChange = (e: React.ChangeEvent<HTMLInputElement>) => {
644
+ const selectedFile = e.target.files?.[0];
645
+ if (selectedFile) {
646
+ setFile(selectedFile);
647
+ }
648
+ };
649
+
650
+ const handleUpload = async () => {
651
+ if (!file) return;
652
+
653
+ setUploading(true);
654
+ try {
655
+ const result = await db.storage.uploadFile(file.name, file);
656
+ if (result.data) {
657
+ toast.success("File uploaded successfully!");
658
+ console.log("File ID:", result.data.id);
659
+ // You can now link this file to other entities
660
+ }
661
+ } catch (error) {
662
+ toast.error("Failed to upload file");
663
+ console.error("Upload error:", error);
664
+ } finally {
665
+ setUploading(false);
666
+ }
667
+ };
668
+
669
+ return (
670
+ <Card>
671
+ <CardHeader>
672
+ <CardTitle>File Upload</CardTitle>
673
+ <CardDescription>Upload files to InstantDB storage</CardDescription>
674
+ </CardHeader>
675
+ <CardContent className="space-y-4">
676
+ <input
677
+ type="file"
678
+ onChange={handleFileChange}
679
+ className="block w-full text-sm text-gray-500 file:mr-4 file:py-2 file:px-4 file:rounded-full file:border-0 file:text-sm file:font-semibold file:bg-blue-50 file:text-blue-700 hover:file:bg-blue-100"
680
+ />
681
+ {file && (
682
+ <div className="text-sm text-muted-foreground">
683
+ Selected: {file.name} ({(file.size / 1024).toFixed(1)} KB)
684
+ </div>
685
+ )}
686
+ <Button
687
+ onClick={handleUpload}
688
+ disabled={!file || uploading}
689
+ className="w-full"
690
+ >
691
+ {uploading ? "Uploading..." : "Upload File"}
692
+ </Button>
693
+ </CardContent>
694
+ </Card>
695
+ );
696
+ }
697
+ ```
698
+
699
+ ## Step 7: App Integration
700
+
701
+ ### Main App Layout
702
+
703
+ Update your main page to include authentication and database features:
704
+
705
+ ```typescript
706
+ // app/page.tsx
707
+ import { AuthProvider, AuthForm } from "@/components/auth/AuthProvider";
708
+ import { PostsList } from "@/components/posts/PostsList";
709
+ import { CreatePostForm } from "@/components/posts/CreatePostForm";
710
+ import { FileUpload } from "@/components/storage/FileUpload";
711
+
712
+ export default function HomePage() {
713
+ return (
714
+ <div className="container mx-auto py-8 space-y-8">
715
+ <h1 className="text-4xl font-bold text-center">My App with InstantDB</h1>
716
+
717
+ <div className="grid grid-cols-1 md:grid-cols-2 gap-8">
718
+ <div>
719
+ <AuthProvider />
720
+ <AuthForm />
721
+ </div>
722
+
723
+ <div className="space-y-6">
724
+ <CreatePostForm />
725
+ <FileUpload />
726
+ </div>
727
+ </div>
728
+
729
+ <PostsList />
730
+ </div>
731
+ );
732
+ }
733
+ ```
734
+
735
+ ## Step 8: Deployment and Configuration
736
+
737
+ ### Push Schema to InstantDB
738
+
739
+ ```bash
740
+ # Install InstantDB CLI
741
+ npm install -g instant-cli
742
+
743
+ # Push your schema
744
+ instant-cli push
745
+
746
+ # Or push just the schema
747
+ instant-cli push schema
748
+ ```
749
+
750
+ ### Environment Variables for Production
751
+
752
+ ```env
753
+ # .env.production
754
+ NEXT_PUBLIC_INSTANT_APP_ID=your_production_app_id
755
+ ```
756
+
757
+ ## Best Practices
758
+
759
+ ### 1. Error Handling
760
+
761
+ Always wrap database operations in try-catch blocks and provide user feedback:
762
+
763
+ ```typescript
764
+ const handleCreatePost = async (data: PostData) => {
765
+ try {
766
+ const result = await dbUtils.create("posts", data);
767
+ if (result.success) {
768
+ toast.success("Post created!");
769
+ } else {
770
+ toast.error(result.error || "Failed to create post");
771
+ }
772
+ } catch (error) {
773
+ toast.error("An unexpected error occurred");
774
+ console.error("Error:", error);
775
+ }
776
+ };
777
+ ```
778
+
779
+ ### 2. Optimistic Updates
780
+
781
+ For better UX, update the UI immediately and rollback on error:
782
+
783
+ ```typescript
784
+ const handleToggleLike = async (postId: string) => {
785
+ // Optimistic update
786
+ setLiked(!liked);
787
+
788
+ try {
789
+ await dbUtils.update("posts", postId, { liked: !liked });
790
+ } catch (error) {
791
+ // Rollback on error
792
+ setLiked(liked);
793
+ toast.error("Failed to update like");
794
+ }
795
+ };
796
+ ```
797
+
798
+ ### 3. Real-time Subscriptions
799
+
800
+ Use specific queries to avoid unnecessary re-renders:
801
+
802
+ ```typescript
803
+ // Good: Specific query
804
+ const { data } = useRealtimeQuery({
805
+ posts: {
806
+ $: { where: { published: true } },
807
+ author: {},
808
+ },
809
+ });
810
+
811
+ // Avoid: Overly broad queries
812
+ const { data } = useRealtimeQuery({ posts: {} });
813
+ ```
814
+
815
+ ## Troubleshooting
816
+
817
+ ### Common Issues
818
+
819
+ 1. **Schema not syncing**: Run `instant-cli push` to sync your schema
820
+ 2. **Authentication not working**: Check your APP_ID in environment variables
821
+ 3. **Real-time updates not working**: Ensure you're using `useRealtimeQuery` for live data
822
+ 4. **Type errors**: Make sure your schema types match your TypeScript interfaces
823
+
824
+ ### Debug Mode
825
+
826
+ Enable debug mode for development:
827
+
828
+ ```typescript
829
+ const db = init({
830
+ appId: process.env.NEXT_PUBLIC_INSTANT_APP_ID,
831
+ schema,
832
+ devtool: true, // Enable InstantDB devtools
833
+ verbose: true, // Enable verbose logging
834
+ });
835
+ ```
836
+
837
+ ## Next Steps
838
+
839
+ 1. **Set up permissions**: Configure `instant.perms.ts` for data access control
840
+ 2. **Add more entities**: Extend your schema based on your app's needs
841
+ 3. **Implement caching**: Use React Query or SWR for additional caching layers
842
+ 4. **Add real-time features**: Implement presence, cursors, and live collaboration
843
+ 5. **Optimize performance**: Use pagination and selective queries for large datasets
844
+
845
+ ## Resources
846
+
847
+ - [InstantDB Documentation](https://instantdb.com/docs)
848
+ - [Magic Code Authentication](https://instantdb.com/docs/auth/magic-codes)
849
+ - [Real-time Queries](https://instantdb.com/docs/reading-data)
850
+ - [File Storage](https://instantdb.com/docs/storage)
851
+ - [InstantDB CLI](https://instantdb.com/docs/instant-cli)