Bolt.new
repository·main·Indexed 12 days ago
https://github.com/stackblitz/bolt.newAn AI-powered, browser-based full-stack development agent that uses StackBlitz WebContainers to run Node.js environments. It allows users to build, run, edit, and deploy applications through natural language prompts with direct control over the filesystem, package managers, and terminal.
What's inside Bolt.new
- Bolt.new is an AI-powered web development agent that enables users to prompt, run, edit, and deploy full-stack applications directly within a browser environment. It eliminates the need for local setup by integrating AI models with StackBlitz's WebContainers, providing a complete development lifecycle from initial scaffolding to production deployment.
How Bolt.new manages the development environment
mainUnlike standard AI code assistants, Bolt.new provides AI models with complete control over the development environment. This includes direct interaction with:
- Filesystem: Creating and editing files.
- Node.js Servers: Running backend processes.
- Package Manager: Installing npm tools and libraries (e.g., Vite, Next.js).
- Terminal: Executing commands.
- Browser Console: Monitoring and interacting with the runtime.
This architecture allows the AI to handle the entire application lifecycle, including interacting with third-party APIs and deploying to production via chat.
Best practices for prompting in Bolt.new
mainTo get the most effective results from the AI agent, follow these prompting strategies:
- Specify your stack: Explicitly mention preferred frameworks or libraries (e.g.,
Astro,Tailwind,ShadCN) in your initial prompt to ensure correct scaffolding. - Scaffold in stages: Build the basic application structure first before requesting advanced features. This ensures the foundation is correctly wired before complexity increases.
- Batch instructions: Combine multiple simple tasks into a single message (e.g., "change the color scheme, add mobile responsiveness, and restart the dev server") to save time and reduce API credit consumption.
- Use the 'enhance' icon: Click the enhance icon before sending a prompt to let the AI help refine and optimize your instructions.
- Specify your stack: Explicitly mention preferred frameworks or libraries (e.g.,
Manage workbench state with WorkbenchStore
mainWorkbenchStoreis the central state management class for the Bolt.new workbench. It orchestrates the state for files, the code editor, terminal, previews, and AI-generated artifacts. It usesnanostoresfor reactive state management.Key responsibilities include:
- File Management: Saving, resetting, and tracking unsaved files.
- Editor State: Managing the current document, selected file, and scroll positions.
- Terminal Control: Toggling visibility and attaching terminal instances.
- Artifact Management: Handling AI-generated artifacts and their associated
ActionRunnerinstances. - View Control: Managing whether the workbench is visible and switching between
codeandpreviewviews.
import { workbenchStore } from '~/lib/stores/workbench'; // Example: Saving the current document await workbenchStore.saveCurrentDocument(); // Example: Switching to preview view workbenchStore.currentView.set('preview'); // Example: Checking for unsaved files const unsaved = workbenchStore.unsavedFiles.get(); console.log(`You have ${unsaved.size} unsaved files.`);How StreamingMessageParser handles streaming text
mainThe
StreamingMessageParseris designed for incremental processing. It maintains aMessageStatefor every uniquemessageIdprovided to the.parse()method.Internal State Management
- Position Tracking: The parser tracks the last processed character index (
position) to ensure it doesn't re-process text or miss partial tags across chunks. - Nesting Logic: It tracks whether the parser is currently
insideArtifactorinsideActionto correctly handle nested tags. - Output Generation: The
.parse()method returns a string containing the text that is not part of a tag. If anartifactElementfactory is provided, the<boltArtifact>tags are replaced in the output with the string returned by that factory.
Workflow
- Chunk 1:
... <boltArtifact id="a" title="t"> ...onArtifactOpenis triggered.- Output contains the
artifactElementplaceholder.
- Chunk 2:
... <boltAction type="shell"> ...onActionOpenis triggered.
- Chunk 3:
... </boltAction> </boltArtifact>onActionCloseandonArtifactCloseare triggered.
- Chunk 4:
...- Parser returns the remaining text normally.
- Position Tracking: The parser tracks the last processed character index (
Manage filesystem state with FilesStore
mainThe
FilesStoreclass manages the state of files and folders within a WebContainer environment. It synchronizes the in-memory file map with the actual filesystem using a path watcher.Key features include:
- Reactive State: Uses
nanostoresto provide afilesMapStore that can be subscribed to for UI updates. - File Tracking: Tracks file modifications to compute diffs, which is useful for informing AI models of changes.
- Binary Detection: Automatically detects if a file is binary to prevent attempting to render or edit non-text content in the editor.
Data Structures:
File:{ type: 'file', content: string, isBinary: boolean }Folder:{ type: 'folder' }FileMap: A record mapping file paths (strings) toFile | Folder | undefined.
import { FilesStore } from '~/lib/stores/files'; // Initialize with a WebContainer promise const filesStore = new FilesStore(webcontainerPromise); // Access the reactive file map filesStore.files.listen((fileMap) => { console.log('Files updated:', fileMap); });- Reactive State: Uses
Configure StreamingMessageParserOptions
mainWhen instantiating
StreamingMessageParser, you can provide aStreamingMessageParserOptionsobject to control callback behavior and UI rendering.Options
callbacks?: ParserCallbacks: An object containing lifecycle hooks:onArtifactOpen?: (data: ArtifactCallbackData) => voidonArtifactClose?: (data: ArtifactCallbackData) => voidonActionOpen?: (data: ActionCallbackData) => voidonActionClose?: (data: ActionCallbackData) => void
artifactElement?: ElementFactory: A function used to generate a string representation of the artifact placeholder in the returned text. It receives{ messageId: string }as an argument.
Callback Data Shapes
ArtifactCallbackData
{ id: string; title: string; messageId: string; }ActionCallbackData
{ artifactId: string; messageId: string; actionId: string; action: BoltAction; // Can be FileAction or ShellAction }Disable chat persistence via environment variable
mainChat persistence can be globally disabled by setting the
VITE_DISABLE_PERSISTENCEenvironment variable. When this variable is present, the database will not be opened, anduseChatHistorywill treat the session as non-persistent, showing a toast error if persistence was expected.# To disable persistence, ensure this env var is set in your environment VITE_DISABLE_PERSISTENCE=trueConfigure UnoCSS for Bolt.new
mainThe project uses UnoCSS for styling. The configuration includes custom presets for icons, theme-aware dark mode, and a comprehensive set of design tokens (colors, shortcuts, and rules).
Key configuration features:
- Presets: Uses
presetUnowith dark mode support via[data-theme="light/dark"]andpresetIconsfor icon management. - Custom Icons: Icons are loaded from the
./icons/*.svgdirectory and registered under theboltcollection. - Transformers: Includes
transformerDirectives()to support@applyand other CSS directives. - Theme Tokens: Extensive use of CSS variables (e.g.,
var(--bolt-elements-...)) for theme-aware components like buttons, sidebars, and terminals.
import { defineConfig, presetIcons, presetUno, transformerDirectives } from 'unocss'; export default defineConfig({ presets: [ presetUno({ dark: { light: '[data-theme="light"]', dark: '[data-theme="dark"]', }, }), presetIcons({ warn: true, collections: { // custom collections }, }), ], transformers: [transformerDirectives()], });- Presets: Uses
Configure ESLint with @blitz/eslint-plugin
mainThe project uses
@blitz/eslint-pluginto provide recommended linting configurations. You can extend the recommended ruleset and apply specific overrides for TypeScript and React files. The configuration also enforces a project-wide rule against relative imports (e.g.,../), requiring the use of the~/alias instead.import blitzPlugin from '@blitz/eslint-plugin'; export default [ ...blitzPlugin.configs.recommended(), // Add custom rules or overrides below ];Retrieve specific chat messages with getMessages()
mainThe
getMessages(db, id)function attempts to find a chat session using two fallback strategies:- It first tries to find the record by its primary
idusinggetMessagesById. - If not found, it attempts to find the record by its
urlIdusinggetMessagesByUrlId.
Returns a
ChatHistoryItemif a match is found, otherwise returnsundefined.import { getMessages } from '~/lib/persistence/db'; const chat = await getMessages(db, 'some-id-or-url-id'); if (chat) { console.log(chat.messages); }- It first tries to find the record by its primary
Delete a chat session with deleteById()
mainUse
deleteById(db, id)to remove a specific chat record from thechatsobject store using its primaryid.import { deleteById } from '~/lib/persistence/db'; await deleteById(db, 'chat-123');