## 1. Project Overview & Quickstart (ben-rogerson/twin.macro)
## File: README.md
---
Style jsx elements using Tailwind classes:
```js
import 'twin.macro'
const Input = () =>
```
Nest Twin’s `tw` import within a css prop to add conditional styles:
```js
import tw from 'twin.macro'
const Input = ({ hasHover }) => (
)
```
Or mix sass styles with the css import:
```js
import tw, { css } from 'twin.macro'
const hoverStyles = css`
&:hover {
border-color: black;
${tw`text-black`}
}
`
const Input = ({ hasHover }) => (
)
```
### Styled Components
You can also use the tw import to create and style new components:
```js
import tw from 'twin.macro'
const Input = tw.input`border hover:border-black`
```
And clone and style existing components:
```js
const PurpleInput = tw(Input)`border-purple-500`
```
Switch to the styled import to add conditional styling:
```js
import tw, { styled } from 'twin.macro'
const StyledInput = styled.input(({ hasBorder }) => [
`color: black;`,
hasBorder && tw`border-purple-500`,
])
const Input = () =>
```
Or use backticks to mix with sass styles:
```js
import tw, { styled } from 'twin.macro'
const StyledInput = styled.input`
color: black;
${({ hasBorder }) => hasBorder && tw`border-purple-500`}
`
const Input = () =>
```
## How it works
When babel runs over your javascript or typescript files at compile time, twin grabs your classes and converts them into css objects.
These css objects are then passed into your chosen css-in-js library without the need for an extra client-side bundle:
```js
import tw from 'twin.macro'
tw`text-sm md:text-lg`
// ↓ ↓ ↓ ↓ ↓ ↓
{
fontSize: '0.875rem',
'@media (min-width: 768px)': {
fontSize: '1.125rem',
},
}
```
## Features
**👌 Simple imports** - Twin collapses imports from common styling libraries into a single import:
```diff
- import styled from '@emotion/styled'
- import css from '@emotion/react'
+ import { styled, css } from 'twin.macro'
```
**🐹 Adds no size to your build** - Twin converts the classes you’ve used into css objects using Babel and then compiles away, leaving no runtime code
**🍱 Apply variants to multiple classes at once with variant groups**
```js
import 'twin.macro'
const interactionStyles = () => (
)
const mediaStyles = () =>
const pseudoElementStyles = () =>
const stackedVariants = () =>
const groupsInGroups = () =>
```
**🛎 Helpful suggestions for mistypings** - Twin chimes in with class and variant values from your Tailwind config:
```bash
✕ ml-1.25 was not found
Try one of these classes:
- ml-1.5 > 0.375rem
- ml-1 > 0.25rem
- ml-10 > 2.5rem
```
**🖌️ Use the theme import to add values from your tailwind config**
```js
import { css, theme } from 'twin.macro'
const Input = () =>
```
See more examples [using the theme import →](https://github.com/ben-rogerson/twin.macro/pull/106)
**💡 Works with the official tailwind vscode plugin** - Avoid having to look up your classes with auto-completions straight from your Tailwind config - [setup instructions →](https://github.com/ben-rogerson/twin.macro/discussions/227)
**💥 Add !important to any class with a trailing or leading bang!**
```js
||
// ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓
```
Add !important to multiple classes with bracket groups:
```js
// ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓
```
## Get started
Twin works with many modern stacks - take a look at these examples to get started:
### App build tools and libraries
- **Parcel**[styled-components](https://github.com/ben-rogerson/twin.examples/tree/master/react-styled-components) / [emotion](https://github.com/ben-rogerson/twin.examples/tree/master/react-emotion) / [emotion (ts)](https://github.com/ben-rogerson/twin.examples/tree/master/react-emotion-typescript)
- **Webpack**[styled-components (ts)](https://github.com/ben-rogerson/twin.examples/tree/master/webpack-styled-components-typescript) / [emotion (ts)](https://github.com/ben-rogerson/twin.examples/tree/master/webpack-emotion-typescript)
- **Preact**[styled-components](https://github.com/ben-rogerson/twin.examples/tree/master/preact-styled-components) / [emotion](https://github.com/ben-rogerson/twin.examples/tree/master/preact-emotion) / [goober](https://github.com/ben-rogerson/twin.examples/tree/master/preact-goober)
- **Create React App**[styled-components](https://github.com/ben-rogerson/twin.examples/tree/master/cra-styled-components) / [emotion](https://github.com/ben-rogerson/twin.examples/tree/master/cra-emotion)
- **Vite**[styled-components (ts)](https://github.com/ben-rogerson/twin.examples/tree/master/vite-styled-components-typescript) / [emotion (ts)](https://github.com/ben-rogerson/twin.examples/tree/master/vite-emotion-typescript) / [solid (ts)](https://github.com/ben-rogerson/twin.examples/tree/master/vite-solid-typescript)
- **Jest / React Testing Library**[styled-components (ts) / emotion (ts)](https://github.com/ben-rogerson/twin.examples/tree/master/jest-testing-typescript)
### Advanced frameworks
- **Next.js**[styled-components](https://github.com/ben-rogerson/twin.examples/tree/master/next-styled-components) / [styled-components (ts)](https://github.com/ben-rogerson/twin.examples/tree/master/next-styled-components-typescript) / [emotion](https://github.com/ben-rogerson/twin.examples/tree/master/next-emotion) / [emotion (ts)](https://github.com/ben-rogerson/twin.examples/tree/master/next-emotion-typescript) / [stitches (ts)](https://github.com/ben-rogerson/twin.examples/tree/master/next-stitches-typescript)
- **T3 App**[styled-components (ts)](https://github.com/ben-rogerson/twin.examples/tree/master/t3-styled-components-typescript) /
[emotion (ts)](https://github.com/ben-rogerson/twin.examples/tree/master/t3-emotion-typescript)
- **Blitz.js**[emotion (ts)](https://github.com/ben-rogerson/twin.examples/tree/master/blitz-emotion-typescript)
- **Gatsby**[styled-components](https://github.com/ben-rogerson/twin.examples/tree/master/gatsby-styled-components) / [emotion](https://github.com/ben-rogerson/twin.examples/tree/master/gatsby-emotion)
### Component libraries
- **Storybook**[styled-components (ts)](https://github.com/ben-rogerson/twin.examples/tree/master/storybook-styled-components-typescript) / [emotion](https://github.com/ben-rogerson/twin.examples/tree/master/storybook-emotion) / [emotion (ts)](https://github.com/ben-rogerson/twin.examples/tree/master/storybook-emotion-typescript)
- **yarn/npm workspaces + Next.js + shared ui components**[styled-components](https://github.com/ben-rogerson/twin.examples/tree/master/component-library-styled-components)
- **Yarn workspaces + Rollup**[emotion](https://github.com/ben-rogerson/twin.examples/tree/master/component-library-emotion)
- [**HeadlessUI** (ts)](https://github.com/ben-rogerson/twin.examples/tree/master/headlessui-typescript)
## Community
[Drop into our Discord server](https://discord.gg/Xj6x9z7) for announcements, help and styling chat.
[](https://discord.gg/Xj6x9z7)
## Resources
- 🔥 [Docs: The prop styling guide](https://github.com/ben-rogerson/twin.macro/blob/master/docs/prop-styling-guide.md) - A must-read guide to level up on prop styling
- 🔥 [Docs: The styled component guide](https://github.com/ben-rogerson/twin.macro/blob/master/docs/styled-component-guide.md) - A must-read guide on getting productive with styled components
- [Docs: Options](https://github.com/ben-rogerson/twin.macro/blob/master/docs/options.md) - Learn about the features you can tweak via the twin config
- [Plugin: babel-plugin-twin](https://github.com/ben-rogerson/babel-plugin-twin) - Use the tw and css props without adding an import
- [Example: Advanced theming](https://github.com/ben-rogerson/twin.macro/blob/master/docs/advanced-theming.md) - Add custom theming the right way using css variables
- [Example: React + Tailwind breakpoint syncing](https://gist.github.com/ben-rogerson/b4b406dffcc18ae02f8a6c8c97bb58a8) - Sync your tailwind.config.js breakpoints with react
- [Helpers: Twin VSCode snippets](https://gist.github.com/ben-rogerson/c6b62508e63b3e3146350f685df2ddc9) - For devs who want to type less
- [Plugins: VSCode plugins](https://github.com/ben-rogerson/twin.macro/discussions/227) - VScode plugins that work with twin
- [Article: "Why I Love Tailwind" by Max Stoiber](https://mxstbr.com/thoughts/tailwind) - Max (inventor of styled-components) shares his thoughts on twin
## Special thanks
This project stemmed from [babel-plugin-tailwind-components](https://github.com/bradlc/babel-plugin-tailwind-components) so a big shout out goes to [Brad Cornes](https://github.com/bradlc) for the amazing work he produced. Styling with tailwind.macro has been such a pleasure.
---
[Consider donating some 🍕 if you enjoy!](https://www.buymeacoffee.com/benrogerson)
---
## File: docs/advanced-theming.md
# Theming with css variables
These examples show how to create themes using css variables rather than relying on the default `dark:` variant supplied in tailwind.
This technique is the preferred way to add a dark/light theme and allows you to add more themes when needed.
- [react + emotion](https://codesandbox.io/s/github/alexperronnet/codesandbox-examples/tree/master/react/twin-emotion-dark-mode-variables)
- [react + styled-components](https://codesandbox.io/s/github/alexperronnet/codesandbox-examples/tree/master/react/twin-styled-components-dark-mode-variables)
- [gatsby + emotion](https://codesandbox.io/s/github/alexperronnet/codesandbox-examples/tree/master/gatsby/twin-emotion-dark-mode-variables)
- [gatsby + styled-components](https://codesandbox.io/s/github/alexperronnet/codesandbox-examples/tree/master/gatsby/twin-styled-components-dark-mode-variables)
---
[‹ Documentation](https://github.com/ben-rogerson/twin.macro/blob/master/docs/index.md)
---
## File: docs/arbitrary-values.md
# Arbitrary values
Twin supports the same arbitrary values syntax popularized by Tailwind’s [jit ("Just-in-Time") mode](https://tailwindcss.com/docs/just-in-time-mode).
```js
tw`top-[calc(100vh - 2rem)]`
// ↓ ↓ ↓ ↓ ↓ ↓
;({ top: 'calc(100vh - 2rem)' })
```
Arbitrary values use square brackets to allow custom css values instead of classes built from your tailwind.config.js.
This is a good solution for those unique “once off” values that every project requires which you may not want to add to your tailwind.config.js.
## Supported classes
Generally the rule is: Dynamic classes - like `bg-red-500` - support arbitrary values, while static classes like `block` don’t.
> For fully custom css properties and values use [arbitrary properties](https://tailwindcss.com/docs/adding-custom-styles#arbitrary-properties).
## Spaces in values
In Tailwind, when we add classes within the className prop/attribute, values cannot have spaces in them.
```js
// Spaced values won’t work in Tailwind
;
```
But with twin, spaces are okay because Twin is not restricted by the spacing rules of the className prop:
```js
// Twin supports values with spaces
;
// Classes can be added on multiple lines when using template literals
;
```
And we can also use Arbitrary values within variant groups:
```js
;
```
## Dynamic values
Just like Tailwind, values can't be dynamically added because Twin doesn’t have the ability to read the variables before converting to a css object:
```js
// Dynamic values without the tw call won’t work
;
```
You’ll need to use a full tw class definition to make dynamic values possible:
```js
// Dynamic values work when constructed like this
;
```
## Resources
- [The PR for arbitrary values](https://github.com/ben-rogerson/twin.macro/pull/447)
---
[‹ Documentation](https://github.com/ben-rogerson/twin.macro/blob/master/docs/index.md)
---
## File: docs/customizing-config.md
# Customizing the Tailwind config
For style customizations, add a `tailwind.config.js` in your project root.
> It’s important to know that you don’t need a `tailwind.config.js` to use Twin. You already have access to every class with every variant.
Choose from one of the following configs:
- a) Start with an empty config:
```js
// tailwind.config.js
module.exports = {
theme: {
extend: {
colors: {},
},
},
plugins: [],
}
```
- b) Start with a [full config](https://raw.githubusercontent.com/tailwindcss/tailwindcss/master/stubs/defaultConfig.stub.js):
```bash
# cd into your project folder then:
npx tailwindcss-cli@latest init --full
```
## Plugins
You can use all Tailwind plugins with twin, some popular ones are [tailwindcss-typography](https://github.com/tailwindlabs/tailwindcss-typography) and [@tailwindcss/forms](https://github.com/tailwindlabs/tailwindcss-forms).
## Resources
- Official [Tailwind theme docs](https://tailwindcss.com/docs/theme)
---
[‹ Documentation](https://github.com/ben-rogerson/twin.macro/blob/master/docs/index.md)
---
## File: docs/fonts.md
# Fonts
You can add `@font-face` definitions either [in the global styles provider](#add-the-font-face-in-the-global-styles-provider) or [in a traditional .css file](#add-the-font-face-in-a-traditional-css-file).
## Add `@font-face` in the Global styles provider
An option is to add the font with the global provider that comes with your css-in-js library. Here are some examples:
### Styled-components
```js
// styles/GlobalStyles.js
import React from 'react'
import { createGlobalStyle } from 'styled-components'
import tw, { theme, GlobalStyles as BaseStyles } from 'twin.macro'
const CustomStyles = createGlobalStyle`
@font-face {
font-family: 'Foo';
src: url('/path/to/exampleFont.woff') format('woff');
font-style: normal;
font-weight: 400;
/* https://styled-components.com/docs/faqs#how-do-i-fix-flickering-text-after-server-side-rendering */
font-display: fallback;
}
`
const GlobalStyles = () => (
<>
>
)
export default GlobalStyles
```
[createGlobalStyle docs →](https://styled-components.com/docs/api#createglobalstyle)
### Emotion
```js
// styles/GlobalStyles.js
import React from 'react'
import { Global, css } from '@emotion/react'
import tw, { theme, GlobalStyles as BaseStyles } from 'twin.macro'
const customStyles = css`
@font-face {
font-family: 'Foo';
src: url('/path/to/exampleFont.woff') format('woff');
font-style: normal;
font-weight: 400;
/* https://styled-components.com/docs/faqs#how-do-i-fix-flickering-text-after-server-side-rendering */
font-display: fallback;
}
`
const GlobalStyles = () => (
<>
>
)
export default GlobalStyles
```
[Global docs →](https://emotion.sh/docs/globals)
### Goober
```js
// styles/GlobalStyles.js
import React from 'react'
import { createGlobalStyle } from 'styled-components'
import tw, { GlobalStyles as BaseStyles } from 'twin.macro'
const CustomStyles = createGlobalStyle`
@font-face {
font-family: 'Foo';
src: url('/path/to/exampleFont.woff') format('woff');
font-style: normal;
font-weight: 400;
/* https://styled-components.com/docs/faqs#how-do-i-fix-flickering-text-after-server-side-rendering */
font-display: fallback;
}
`
const GlobalStyles = () => (
<>
>
)
export default GlobalStyles
```
[createGlobalStyle docs →](https://goober.js.org/api/createGlobalStyles)
## Add the `@font-face` in a .css file and import it
This method may help to remove text flickering in some frameworks.
```css
/* styles/fonts.css */
@font-face {
font-family: 'Foo';
src: url('/path/to/exampleFont.woff') format('woff');
font-style: normal;
font-weight: 400;
font-display: fallback;
}
```
```js
// index.js / _app.js
import '../styles/fonts.css'
// ...
```
---
[‹ Documentation](https://github.com/ben-rogerson/twin.macro/blob/master/docs/index.md)
---
## File: docs/group.md
# Using the group className
There’s a couple of Tailwind classes that need to be added to React elements as a `className`.
These classes are the `peer` and the `group` classes.
A className is used so variants like `group-hover:` and `peer-hover:` can use the className as an anchor to allow their styles to work.
Here’s how we use the `group` classes in twin:
```js
import 'twin.macro'
export default () => (
Child 1
Child 2
)
```
When working in emotion and styled-components without the `group` classes, the equivalent looks like this:
```js
import tw, { styled } from 'twin.macro'
const Group = tw.button``
Group.Child1 = styled.div`
${Group}:hover & {
${tw`bg-black`}
}
`
Group.Child2 = styled.div`
${Group}:hover & {
${tw`font-bold`}
}
`
export default () => (
Child 1
Child 2
)
```
Not as great right?
Here’s some ways you can improve upon that:
## Attrs in 💅 styled‑components
In styled-components we have a `styled` function called `attrs`.
Here’s what the docs have to say about it:
> The rule of thumb is to use attrs when you want every instance of a styled component to have that prop, and pass props directly when every instance needs a different one.- [styled-components docs](https://styled-components.com/docs/faqs#when-to-use-attrs)
But we can also put it to use to define the `group` class in Tailwind.
Rather than adding `className="group"` directly onto your jsx element, the class can be more tightly coupled with your styles:
```js
import tw, { styled } from 'twin.macro'
const Group = styled.button.attrs({ className: 'group' })``
Group.Child1 = tw.div`group-hover:bg-black`
Group.Child2 = tw.div`group-hover:font-bold`
export default () => (
Child 1
Child 2
)
```
## Attrs in emotion
Unfortunately emotion [doesn’t have any plans](https://github.com/emotion-js/emotion/issues/821) to add `attrs` so the easiest option is to add `className="group"` directly on the jsx element:
```js
import tw from 'twin.macro'
const Group = tw.button``
Group.Child1 = tw.div`group-hover:bg-black`
Group.Child2 = tw.div`group-hover:font-bold`
export default () => (
Child 1
Child 2
)
```
But if you’d like similar functionality to the attr function in styled-components then you could add the className using a [Higher-Order Component (HOC)](https://reactjs.org/docs/higher-order-components.html):
```js
import tw from 'twin.macro'
const withAttrs = (Component, attrs) => props =>
const Button = tw.button``
const Group = withAttrs(Button, { className: 'group' })
Group.Child1 = tw.div`group-hover:bg-black`
Group.Child2 = tw.div`group-hover:font-bold`
export default () => (
Child 1
Child 2
)
```
You could also use `defaultProps` but it’s [deprecated in React 18.3+](https://react.dev/blog/2024/04/25/react-19-upgrade-guide#removed-deprecated-react-apis) and removed in React 19:
```js
import tw from 'twin.macro'
const Group = tw.button``
Group.defaultProps = { className: 'group' }
Group.Child1 = tw.div`group-hover:bg-black`
Group.Child2 = tw.div`group-hover:font-bold`
export default () => (
Child 1
Child 2
)
```
## Resources
- [Quick Start Guide to Attrs in styled-components](https://scalablecss.com/styled-components-attrs/)
- [Emotion issue: .attrs equivalent](https://github.com/emotion-js/emotion/issues/821)
---
[‹ Documentation](https://github.com/ben-rogerson/twin.macro/blob/master/docs/index.md)
---
## File: docs/index.md
[](#documentation)
# Documentation
[](#usage)
## Usage
- [The prop styling guide](./prop-styling-guide.md)
- [Styled component guide](./styled-component-guide.md)
[](#configuration)
## Configuration
- [Twin config options](./options.md)
- [Customizing the tailwind config](./customizing-config.md)
- [Fonts](./fonts.md)
[](#theming)
## Theming
- [Theming with css variables](./advanced-theming.md)
[](#classes)
## More
- [group](./group.md)
---
## File: docs/options.md
[](#twin-config-options)
# Twin config options
These options are available in your [twin config](#twin-config-location):
| Name | Default | Description |
| --------------------------- | ---------------------- | ----------------------------------------------------------------------------------------------------------------------------------- |
| config | `"tailwind.config.js"` | The path to your Tailwind config. Also takes a config object. |
| preset | `"emotion"` | The css-in-js library behind the scenes.Also supported: `"styled-components"` `"goober"` `"stitches"` `"solid"` |
| dataTwProp | `true` | Add a prop to jsx components in development showing the original tailwind classes. Use `"all"` to keep the prop in production. |
| debug | `false` | Display information in your terminal about the Tailwind class conversions. |
| disableShortCss | `true` | Disable converting short css within the tw import/prop. |
| hasLogColors | `true` | Disable log colors to remove the glyphs when the color display is not supported |
| includeClassNames | `false` | Check className attributes for tailwind classes to convert. |
| dataCsProp | `true` | Add a prop to your elements in development so you can see the original cs prop classes, eg: ``. |
| disableCsProp | `true` | Disable twin from reading values specified in the cs prop. |
| sassyPseudo | `false` | Some css-in-js frameworks require the `&` in selectors like `&:hover`, this option ensures it’s added. |
| moveKeyframesToGlobalStyles | `false` | `@keyframes` are added next to the `animation-x` classes - this option can move them to global styles instead. |
### Options
---
**config**
```js
config: 'tailwind.config.js', // Path to the tailwind config
```
Set a custom location by specifying a path to your tailwind.config.js file.
**Passing in a config**: The config option also accepts a config object:
```js
// babel-plugin-macros.config.js
const tailwindConfig = {
theme: {
extend: {
colors: {
primary: '#ff0000',
},
},
},
}
module.exports = {
twin: {
config: tailwindConfig,
},
}
```
This can be useful in component libraries, tests, or just to remove the need for a tailwind.config.js file.
**Monorepos / Workspaces**: The tailwind.config.js is commonly added as a shared file in the project root so you may need to add a `path.resolve` on the pathname in the twin config:
```js
// babel-plugin-macros.config.js
const path = require('path')
module.exports = {
twin: {
config: path.resolve(__dirname, '../../', 'tailwind.config.js'),
},
}
```
---
**preset**
```js
preset: 'emotion', // Set the css-in-js library to use with twin
```
Supports: `'emotion'` / `'styled-components'` / `'goober'` / `'stitches'`.
The preset option primarily assigns the library imports for `css`, `styled` and `GlobalStyles`.
---
**dataTwProp**
```js
dataTwProp: false, // Set the display of the data-tw prop on jsx elements
```
The `data-tw` prop gets added to your elements while in development so you can see the original tailwind classes:
```js
```
If you add the value `all`, twin will add the data-tw prop in production as well as development.
---
**debug**
```js
debug: true, // Display information about class conversions
```
When debug mode is on, twin displays logs on class conversions.
This feedback only displays in development.
##
---
**hasLogColors**
```js
hasLogColors: false, // Disable log colors (removes those glyphs in your console/overlay)
```
Sometimes the display of errors and suggestions are pretty poor due to lack of support for custom colors. Use this setting to disable the colors so you can actually read the messages.
---
**disableShortCss**
```js
disableShortCss: false, // Enable converting short css within the tw import/prop
```
When set to `true`, this will throw an error if short css is added within the tw import or tw prop.
Disable short css completely with `dataCsProp: false`.
---
**includeClassNames**
```js
includeClassNames: true, // Check className props for tailwind classes to convert
```
When a tailwind class is found in a className prop, it’s plucked out, converted and delivered to the css-in-js library.
- Unmatched classes are skipped and preserved within the className
- Suggestions aren’t shown for unmatched classes like they are for the tw prop
- The tw and css props can be used on the same jsx element
- Limitation: classNames with conditional props or variables aren’t touched, eg: ``
---
**dataCsProp**
```js
dataCsProp: false, // JSX prop twin adds that shows the original cs prop classes
```
If you add short css within the `cs` prop then twin will add a `data-cs` prop to preserve the css you added.
This option controls the display of the prop.
Shows in development only.
---
**disableCsProp**
```js
disableCsProp: true, // Whether to read short css values added in a `cs` prop
```
If you're using the cs prop for something else or don’t want other developers using the feature you can disable it with this option.
---
**sassyPseudo**
```js
sassyPseudo: true, // Prefix pseudo selectors with a `&`
```
Some css-in-js frameworks require the `&` in selectors like `&:hover`, this option ensures it’s added.
---
**moveKeyframesToGlobalStyles**
```js
moveKeyframesToGlobalStyles: true, // Avoid @keyframes next to animation-x classes
```
Add `@keyframes` matching an `animation-x` class to global styles instead of alongside the `animation-x` class.
In stitches this gets set to `true` to make animations work.
---
[](#twin-config-location)
## Twin config location
Twin’s config can be added in a couple of different files.
a) Either in `babel-plugin-macros.config.js`:
```js
// babel-plugin-macros.config.js
module.exports = {
twin: {
// add options here
},
}
```
b) Or in `package.json`:
```js
// package.json
"babelMacros": {
"twin": {
// add options here
}
},
```
---
[‹ Documentation index](https://github.com/ben-rogerson/twin.macro/blob/master/docs/index.md)
---
## File: docs/prop-styling-guide.md
# The prop styling guide
## Basic styling
Use Twin’s tw prop to add Tailwind classes onto jsx elements:
```js
import 'twin.macro'
const Component = () => (
)
```
- Use the tw prop when conditional styles aren’t needed
- Any import from `twin.macro` activates the tw prop
- Remove the need for an import with [babel-plugin-twin](https://github.com/ben-rogerson/babel-plugin-twin)
## Conditional styling
To add conditional styles, nest the styles in an array and use the `css` prop:
```js
import tw from 'twin.macro'
const Component = ({ hasBg }) => (
)
```
TypeScript example
```tsx
import tw from 'twin.macro'
interface ComponentProps {
hasBg?: string
}
const Component = ({ hasBg }: ComponentProps) => (
)
```
- Twin doesn’t own the css prop, the prop comes from your css-in-js library
- Adding values to an array makes it easier to define base styles, conditionals and vanilla css
- Use multiple lines to organize styles within the backticks ([template literals](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals))
## Overriding styles
Use the `tw` prop after the css prop to add any overriding styles:
```js
import tw from 'twin.macro'
const Component = () => (
Has black text
)
```
## Keeping jsx clean
It’s no secret that when tailwind class sets become larger, they obstruct the readability of other jsx props.
To clean up the jsx, lift the styles out and group them as named entries in an object:
```js
import tw from 'twin.macro'
const styles = {
container: ({ hasBg }) => [
tw`flex w-full`, // Add base styles first
hasBg && tw`bg-black`, // Then add conditional styles
],
column: tw`w-1/2`,
}
const Component = ({ hasBg }) => (
)
```
TypeScript example
```js
import tw from 'twin.macro'
interface ContainerProps {
hasBg?: boolean;
}
const styles = {
container: ({ hasBg }: ContainerProps) => [
tw`flex w-full`, // Add base styles first
hasBg && tw`bg-black`, // Then add conditional styles
],
column: tw`w-1/2`,
}
const Component = ({ hasBg }: ContainerProps) => (
)
```
## Variants with many values
When a variant has many values (eg: `variant="light/dark/etc"`), name the class set in an object and use a prop to grab the entry containing the styles:
```js
import tw from 'twin.macro'
const containerVariants = {
// Named class sets
light: tw`bg-white text-black`,
dark: tw`bg-black text-white`,
crazy: tw`bg-yellow-500 text-red-500`,
}
const styles = {
container: ({ variant = 'dark' }) => [
tw`flex w-full`,
containerVariants[variant], // Grab the variant style via a prop
],
column: tw`w-1/2`,
}
const Component = ({ variant }) => (
)
```
TypeScript example
Use the `TwStyle` import to type tw blocks:
```tsx
import tw, { TwStyle } from 'twin.macro'
type WrapperVariant = 'light' | 'dark' | 'crazy'
interface ContainerProps {
variant?: WrapperVariant
}
const containerVariants: Record = {
// Named class sets
light: tw`bg-white text-black`,
dark: tw`bg-black text-white`,
crazy: tw`bg-yellow-500 text-red-500`,
}
const styles = {
container: ({ variant = 'dark' }: ContainerProps) => [
tw`flex w-full`,
containerVariants[variant], // Grab the variant style via a prop
],
column: tw`w-1/2`,
}
const Component = ({ variant }: ContainerProps) => (
)
```
## Interpolation workaround
Due to Babel limitations, tailwind classes and arbitrary properties can’t have any part of them dynamically created.
So interpolated values like this won’t work:
```js
// Won't work with tailwind classes
// Won't work with arbitrary properties
```
This is because babel doesn’t know the values of the variables and so twin can’t make a conversion to css.
Instead, define the classes in objects and grab them using props:
```js
import tw from 'twin.macro'
const styles = { sm: tw`mt-2`, lg: tw`mt-4` }
const Component = ({ spacing = 'sm' }) =>
```
Or combine vanilla css with twins `theme` import:
```js
import { theme } from 'twin.macro'
// Use theme values from your tailwind config
const styles = { sm: theme`spacing.2`, lg: theme`spacing.4` }
const Component = ({ spacing = 'sm' }) => (
)
```
Or we can always fall back to vanilla css, which can interpolate anything:
```js
import 'twin.macro'
const Component = ({ width = 5 }) =>
```
## Custom selectors (Arbitrary variants)
Use square-bracketed arbitrary variants to style elements with a custom selector:
```js
import tw from 'twin.macro'
const buttonStyles = tw`
bg-black
[> i]:block
[> span]:(text-blue-500 w-10)
`
const Component = () => (
*Icon*
Label
)
```
More examples
```js
// Style the current element based on a theming/scoping className
;
Dark theme
// Add custom group selectors
;
Text gray
// Add custom height queries
;
This window is less than 800px height
// Use custom at-rules like @supports
;A grid
// Style the current element based on a dynamic className
const Component = ({ isLarge }) => (
...
)
```
## Custom class values (Arbitrary values)
Custom values can be added to many tailwind classes by using square brackets to define the custom value:
```js
;
// ↓ ↓ ↓ ↓ ↓ ↓
```
[Read more about Arbitrary values →](https://github.com/ben-rogerson/twin.macro/blob/master/docs/arbitrary-values.md)
## Custom css
Basic css is added using [arbitrary properties](https://tailwindcss.com/docs/adding-custom-styles#arbitrary-properties) or within vanilla css which supports more advanced use cases like dynamic/interpolated values.
### Simple css styling
To add simple custom styling, use [arbitrary properties](https://tailwindcss.com/docs/adding-custom-styles#arbitrary-properties):
```js
// Set css variables
// Set vendor prefixes
// Set grid areas
```
Use arbitrary properties with variants or twins grouping features:
```js
```
Arbitrary properties also work with the `tw` import:
```js
import tw from 'twin.macro'
;
```
- Add a bang to make the custom css !important: `![grid-area:1 / 1 / 4 / 2]`
- Arbitrary properties can have camelCase properties: `[gridArea:1 / 1 / 4 / 2]`
### Advanced css styling
The css prop accepts a sass-like syntax, allowing both custom css and tailwind styles with values that can come from your tailwind config:
```js
import tw, { css, theme } from 'twin.macro'
const Components = () => (
)
```
But it’s often cleaner to use an object to add styles as it avoids the interpolation cruft seen above:
```js
import tw, { css, theme } from 'twin.macro'
const Components = () => (
)
```
## Learn more
- [Styled component guide](https://github.com/ben-rogerson/twin.macro/blob/master/docs/styled-component-guide.md) - A must-read guide on getting productive with styled-components
## Resources
- [babel-plugin-twin](https://github.com/ben-rogerson/babel-plugin-twin) - Use the tw and css props without adding an import
- [React + Tailwind breakpoint syncing](https://gist.github.com/ben-rogerson/b4b406dffcc18ae02f8a6c8c97bb58a8) - Sync your tailwind.config.js breakpoints with react
- [Twin VSCode snippits](https://gist.github.com/ben-rogerson/c6b62508e63b3e3146350f685df2ddc9) - For devs who want to type less
- [Twin VSCode extensions](https://github.com/ben-rogerson/twin.macro/discussions/227) - For faster class suggestions and feedback
---
[‹ Documentation](https://github.com/ben-rogerson/twin.macro/blob/master/docs/index.md)
---
## File: docs/screen-import.md
# Screen import
The screen import creates media queries for custom css that sync with your tailwind config screen values (sm, md, lg, etc).
**Usage with the css prop**
```js
import tw, { screen, css } from 'twin.macro'
const styles = [
screen`sm`({ display: 'block', ...tw`inline` }),
]
```
**Usage with styled components**
```js
import tw, { styled, screen, css } from 'twin.macro'
const Component = styled.div(() => [
screen`sm`({ display: 'block', ...tw`inline` }),
])
```
## Screen as a key
Without the styles, the screen import just creates a media query, so you can use it as a key:
```js
// ↓ ↓ ↓ ↓ ↓ ↓
```
## Relaxed usage
The screen import can be used in different ways:
```js
screen`sm`({ ... })
screen('sm')({ ... })
screen(`sm`)({ ... })
screen.sm({ ... }) // Dot syntax can’t be used when the screen begins with a number, eg: screen.2xl
```
## Custom media queries
Since the screen import always adds a min-width query, it’s not suitable for constructing custom media queries.
So to add custom media queries, use the theme import instead.
**With the css prop**
```js
import tw, { theme } from 'twin.macro'
const styles = {
[`@media (max-width: ${theme`screens.sm`})`]: {
display: 'block',
...tw`inline`,
},
}
;
```
**With a styled component**
```js
import tw, { styled, theme } from 'twin.macro'
const Component = styled.div({
[`@media (max-width: ${theme`screens.sm`})`]: {
display: 'block',
...tw`inline`,
},
})
```
---
[‹ Documentation](https://github.com/ben-rogerson/twin.macro/blob/master/docs/index.md)
## 2. Official Technical Reference & Guides (ben-rogerson/docs)
## File: README.md
# PlanetScale Documentation
👋 Welcome to the PlanetScale Documentation repo!
## Request content
If you'd like to request content around using PlanetScale or general MySQL/database questions we'd love to hear from you!
Head over to the [Issues tab](https://github.com/planetscale/docs/issues), click "New issue", and select the appropriate template.
## Contribute to docs
We welcome contributions to the PlanetScale documentation! If you have a fix for an existing issue or you found a typo/bug, you can [open a new PR](https://github.com/planetscale/docs/pulls) in this repo.
For larger pull requests, such as language/framework quickstarts, we ask that you [open an issue](https://github.com/planetscale/docs/issues) to request the new content instead of creating it yourself.
## PlanetScale resources
You can find more tutorials, content, and support in the following places:
- [PlanetScale Blog](https://planetscale.com/blog) — PlanetScale tutorials, product information, MySQL/database tips, engineering content, and more
- [PlanetScale YouTube](https://www.youtube.com/c/PlanetScale) — PlanetScale tutorials, recorded conference/stream talks, and more.
- [PlanetScale Twitch](https://www.twitch.tv/planetscale) — Follow us on the PlanetScale Twitch channel for livestreams from PlanetScale employees and guests.
- [PlanetScale Support](https://support.planetscale.com/) — Get in touch with our Support team, read about known issues, and more.
- [PlanetScale discussion board](https://github.com/planetscale/discussion/discussions) — Have a specific question? Join the conversation in our PlanetScale discussion board.
---
## File: docs/tutorials/automatic-prisma-migrations.md
---
title: 'Automatic Prisma migrations'
subtitle: 'How to make changes to your PlanetScale database schema while using Prisma, a next-generation Node.js and TypeScript ORM'
date: '2022-11-29'
---
{% callout %}
This document has been updated to include the recommended Prisma and PlanetScale workflow, specifically the
recommendation to use `prisma db push` instead of `prisma migrate dev` with shadow branches. Also, you previously
needed to turn on the ability to automatically copy the Prisma migration metadata. You no longer need to do this. Read
more below.
{% /callout %}
## Introduction
In this tutorial, we're going to learn how to do Prisma migrations in PlanetScale as part of your deployment process using `prisma db push`.
### Quick introduction to Prisma's db push
From a high level, [Prisma's `db push`](https://www.prisma.io/docs/concepts/components/prisma-migrate/db-push) introspects your PlanetScale database to infer and execute the changes required to make your database schema reflect the state of your Prisma schema. When `prisma db push` is run, it will ensure the schema in the PlanetScale branch you are currently connected to matches your current Prisma schema.
We recommend `prisma db push` over `prisma migrate dev` for the following reasons:
PlanetScale provides [Online Schema Changes](/docs/learn/how-online-schema-change-tools-work) that are deployed automatically when you merge a deploy request and prevents [blocking schema changes](/docs/concepts/nonblocking-schema-changes) that can lead to downtime. This is different from the typical Prisma workflow which uses `prisma migrate` in order to generate SQL migrations for you based on changes in your Prisma schema. When using PlanetScale with Prisma, the responsibility of applying the changes is on the PlanetScale side. Therefore, there is little value to using `prisma migrate` with PlanetScale.
Also, the migrations table created when `prisma migrate` runs can also be misleading since PlanetScale does the actual migration when the deploy request is merged, not when `prisma migrate` is run which only updates the schema in the development database branch. You can still see the history of your schema changes in PlanetScale.
## Prerequisites
- Add Prisma to your project using `npm install prisma --save-dev` or `yarn add prisma --dev` (depending on what package manager you prefer).
- Run `npx prisma init` inside of your project to create the initial files needed for Prisma.
- Install the [PlanetScale CLI](https://github.com/planetscale/cli).
- Authenticate the CLI with the following command:
```bash
pscale auth login
```
## Execute your first Prisma db push
Prisma migrations follow the PlanetScale [non-blocking schema change](/docs/concepts/nonblocking-schema-changes) workflow. First, the schema is applied to a _development_ branch and then the development branch is merged into the `main` production database.
Let's begin with an example flow for running Prisma migrations in PlanetScale:
1. Create a new _prisma-playground_ database:
```bash
pscale db create prisma-playground
```
2. Connect to the database branch:
```bash
pscale connect prisma-playground main --port 3309
```
{% callout %}
This step assumes you created a new PlanetScale database and the `main` branch has not been promoted to production
yet. You will need to create a new development branch if the `main` branch has been promoted to production.
{% /callout %}
3. Update your `prisma/schema.prisma` file with the following schema:
{% callout %}
In Prisma `4.5.0`, `referentialIntegrity` changed to `relationMode` and became generally available in `4.7.0`. The following schema reflects this change.
You can learn more about Prisma's Relation mode in the
[Prisma docs](https://www.prisma.io/docs/concepts/components/prisma-schema/relations/relation-mode).
{% /callout %}
```js
datasource db {
provider = "mysql"
url = env("DATABASE_URL")
relationMode = "prisma"
}
generator client {
provider = "prisma-client-js"
}
model Post {
id Int @default(autoincrement()) @id
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
title String @db.VarChar(255)
content String?
published Boolean @default(false)
author User @relation(fields: [authorId], references: [id])
authorId Int
}
model Profile {
id Int @default(autoincrement()) @id
bio String?
user User @relation(fields: [userId], references: [id])
userId Int @unique
}
model User {
id Int @default(autoincrement()) @id
email String @unique
name String?
posts Post[]
profile Profile?
}
```
4. Update your `.env` file:
```shell
DATABASE_URL="mysql://root@127.0.0.1:3309/prisma-playground"
```
6. In another terminal, use the `db push` command to push the schema defined in `prisma/schema.prisma`:
```bash
npx prisma db push
```
Unlike the `prisma migrate dev` command, it will not create a migrations folder containing a SQL file with the SQL used to update the schema in your PlanetScale database. PlanetScale will be tracking your migrations in this workflow.
{% callout type="tip" %}
You can learn more about the `prisma db push` command in the
[Prisma docs](https://www.prisma.io/docs/concepts/components/prisma-migrate/db-push).
{% /callout %}
After `db push` is successful, you can see the table created in your terminal. For example, to see the `Post` table:
```bash
pscale shell prisma-playground main
```
```sql
describe Post;
```
{% callout type="tip" %}
Use the `exit` command to exit the MySQL shell.
{% /callout %}
Or you can see it in the PlanetScale UI under the Schema tab in your `main` branch.
7. Now that the initial schema has been added, promote your `main` branch to production status:
```bash
pscale branch promote prisma-playground main
```
## Execute succeeding Prisma migrations in PlanetScale
Our first example migration flow went well, but what happens when you need to run further changes to your schema?
Let's take a look:
1. Create a new _development_ branch from `main` called `add-subtitle-to-posts`:
```bash
pscale branch create prisma-playground add-subtitle-to-posts
```
2. Close the proxy connection to your `main` branch (if still open) and connect to the new `add-subtitle-to-posts` development branch:
```bash
pscale connect prisma-playground add-subtitle-to-posts --port 3309
```
4. In the `prisma/schema.prisma` file, update the `Post` model:
Add a new `subtitle` field to `Post`:
```
subtitle String @db.VarChar(255)
```
5. Run `db push` again to update the schema in PlanetScale:
```bash
npx prisma db push
```
6. Open a deploy request for your `add-subtitle-to-posts` branch, so that you can deploy these changes to `main`.
You can complete the deploy request either in the web app or with the `pscale deploy-request` command.
```bash
pscale deploy-request create prisma-playground add-subtitle-to-posts
```
```bash
pscale deploy-request deploy prisma-playground 1
```
7. Once the deploy request is merged, you can see the results in your main branch's `Post` table:
```bash
pscale shell prisma-playground main
```
```sql
describe Post;
```
## What's next?
Now that you've successfully conducted your first automatic Prisma migration in PlanetScale and know how to handle future migrations, it's time to deploy your application with a PlanetScale database! Let's learn how to [deploy an application with a PlanetScale database to Vercel](/docs/tutorials/deploy-to-vercel).
---
## File: docs/tutorials/automatic-rails-migrations.md
---
title: 'Automatic Rails migrations'
subtitle: 'To ensure PlanetScale works well with a traditional Rails development process, we implemented the ability to automatically copy Rails migration metadata as part of our deployment process.'
date: '2022-08-01'
---
{% callout type="tip" %}
If you are using PlanetScale with a Rails application, go to your database's Settings page in the web app and enable
"Automatically copy migration data." Select "Rails/Phoenix" as the migration framework. When enabled, this setting
updates the _schema_migrations_ table each time you branch with the latest migration. If disabled, running
_rake db:migrate_ will try to run all migrations every time, instead of only the latest one.
{% /callout %}
## Introduction
In this tutorial, you're going to learn how Rails migrations work with the PlanetScale branching and deployment workflows.
{% callout %}
Migration tracking works with any migration tool, not just Rails. For other frameworks, specify the migration table name on your database's Settings page.
{% /callout %}
## Prerequisites
Follow the [Connect a Rails app](/docs/tutorials/connect-rails-app) tutorial first. By the end, you will have:
- Installed the [PlanetScale CLI](https://github.com/planetscale/cli), Ruby, and the Rails gem
- Created a PlanetScale database named `blog`
- Started a new Rails app named `blog` with a migration creating a `Users` table
- Run the first Rails migration
### A quick introduction to Rails migrations
Rails tracks an application's migrations in an internal table called `schema_migrations`. At a high level, running `rake db:migrate` does the following:
- Rails looks at all of the migration files in your `db/migrate` directory.
- Rails queries the `schema_migrations` table to see which migrations have and haven't been run.
- Any migration that doesn’t appear in the `schema_migrations` table is considered pending and is executed by this task.
{% callout type="tip" %}
When you merge a deploy request in PlanetScale, the _schema_migrations_ table in _main_ is
automatically updated with the migration data from your branch.
{% /callout %}
## Execute a Rails migration on PlanetScale
Rails migrations follow the PlanetScale [non-blocking schema change](/docs/concepts/nonblocking-schema-changes) workflow. First, the migration is applied to a _development_ branch, and then the development branch is merged into the `main` production branch.
Let's add another table to your existing `blog` schema:
1. Create an `add-posts-table` development branch from `main` in your database _blog_:
```bash
pscale branch create blog add-posts-table
```
When the branch is ready, you can verify that the `schema_migrations` table is up-to-date with `main` by checking for the timestamp of your `Create Users` migration file. Your migration will have a different timestamp than the one shown here.
Check the timestamp in your codebase:
```bash
ls db/migrate
20211014210422_create_users.rb
```
Connect to the new branch:
```bash
pscale shell blog add-posts-table
```
Query the migration table:
```sql
blog/add-posts-table> select * from schema_migrations;
+----------------+
| version |
+----------------+
| 20211014210422 |
+----------------+
```
2. Connect your development environment to the new branch:
One way to do this is to create a new password for the `add-posts-table` branch and update `config/database.yml` with the new username, password, and host. Another is to use `pscale connect` to establish a secure connection on a local port. Since the `add-posts-table` branch won't be needed after the migration, let's use the `pscale connect` proxy.
In a separate terminal, establish the connection:
```bash
pscale connect blog add-posts-table --port 3309
```
Then, update `config/database.yml` to connect through the proxy:
```yaml
development:
<<: *default
adapter: mysql2
database: blog
host: 127.0.0.1
port: 3309
```
3. Create the second Rails migration and call it `CreatePosts`:
```bash
rails generate migration CreatePosts
```
Find the new migration file in `db/migrate` and add a few details for the new Posts table:
```ruby
class CreatePosts < ActiveRecord::Migration[7.0]
def change
create_table :posts do |t|
t.string :title
t.text :content
t.bool :published
t.references :user
t.timestamps
end
end
end
```
4. Run the CreatePosts migration:
```bash
rake db:migrate
```
This command runs the new migration against your `add-posts-table` _development_ branch.
At this point, Rails creates the `posts` table and inserts another `timestamp` into the `schema_migrations` table on your development branch.
You can verify the change in `schema_migrations` yourself:
```sql
blog/add-posts-table> select * from schema_migrations;
+----------------+
| version |
+----------------+
| 20211014210422 |
| 20220224221753 |
+----------------+
```
5. Open a deploy request for your `add-posts-table` branch, and deploy your changes to `main`.
You can complete the deploy request either in the web app or with the `pscale deploy-request` command.
```bash
pscale deploy-request create blog add-posts-table
```
```bash
pscale deploy-request deploy blog 1
```
To create the deploy request, PlanetScale looks at the differences between the schemas of `main` and `add-posts-table` and plans a `create table` statement to add the new table to `main`. When you deploy, PlanetScale runs that ` create table` statement and copies the second row from `schema_migrations` in `add-posts-table` to the `schema_migrations` table in `main`.`
6. Verify the changes in your `main` branch:
In a `pscale` shell for `main` you can verify that the changes from `add-posts-table` were deployed successfully.
```bash
pscale shell blog main
```
```sql
blog/|⚠ main ⚠|> show tables;
+----------------------+
| Tables_in_blog |
+----------------------+
| posts |
| schema_migrations |
| users |
+----------------------+
blog/|⚠ main ⚠|> select * from schema_migrations;
+----------------+
| version |
+----------------+
| 20220223232425 |
| 20220224221753 |
+----------------+
```
## Summary
In this tutorial, we learned how to use the PlanetScale deployment process with the Rails migration workflow.
## What's next?
Learn more about how PlanetScale allows you to make [schema changes](/docs/concepts/nonblocking-schema-changes) to your production databases without downtime or locking tables.
---
## File: docs/tutorials/aws-lambda-connection-strings.md
---
title: 'AWS Lambda connection strings'
subtitle: 'Learn how to securely use your PlanetScale MySQL connection strings with AWS Lambda Functions'
date: '2022-08-01'
---
## Introduction
In this guide, you'll learn how to properly store and use PlanetScale MySQL connection strings for use in AWS Lambda Functions. We'll use a [pre-built NodeJS](https://github.com/planetscale/aws-connection-strings-example) app for this example, but you can follow along using your own application as well.
## Prerequisites
- An AWS account
- A [free PlanetScale account](https://auth.planetscale.com/sign-up)
## Set up the database
{% callout %}
If you already have a database with a production branch, skip to [the next section](#configure-the-lambda-function).
{% /callout %}
Let's start by creating the database. In the PlanetScale dashboard, click the "**New database**" button followed by "**Create new database**". Name the database **lambda-connection-strings,** or any other name that you prefer. Click "**Create database**".
Once your database has finished initializing, access the console of the main branch by heading to **Branches** in the top nav, followed by **main**, then **Console**.
Create a simple table & insert some data using the following script:
```sql
CREATE TABLE Tasks(
Id int PRIMARY KEY AUTO_INCREMENT,
Name varchar(100),
IsDone bit
);
INSERT INTO Tasks (Name) VALUES ('Clean the kitchen');
INSERT INTO Tasks (Name) VALUES ('Fold the laundry');
INSERT INTO Tasks (Name) VALUES ('Watch the sportsball game');
```
You may run `SELECT * FROM Tasks` to ensure the data was properly added from the console.
Now we need to promote the **main** branch to production. Click the **Overview** tab, then **Promote a branch to production**. Since there is only one branch, it will be selected by default in the confirmation modal. Click on **Promote branch**.
Before moving on from the PlanetScale dashboard, grab the connection details to be used in the next step. Click on the **Connect** button in the upper right, select **NodeJS** from the **Connect with** dropdown, and note the details in the .env tab of the modal. These details will be required to connect to the database.
## Configure the Lambda function
Secrets in AWS Lambda functions, which include database connection strings, are often stored as environment variables with the Lambda function. We’ll be uploading a sample NodeJS app that has been provided and storing the connection string from the previous section as an environment variable to test.
Start by cloning the following Git repository:
```bash
git clone https://github.com/planetscale/aws-connection-strings-example.git
```
Log into the AWS Console, use the universal search to search for ‘**Lambda**’, and select it from the list of services.
Create a new function using the **Create function** button in the upper right of the console.
Name your function **lambda-connection-strings** (or any other name that suits you) and select **NodeJS** under **Runtime**. The other fields can be left as default. Click **Create function** to finish the initial setup of your Lambda.
On the next view, about halfway down the page you’ll see a section called **Code source**. Click the **Upload from** button, then **.zip file**.
Click the **Upload** button which will display a file browser. Select the **aws-connection-strings-example.zip** file from the **dist** folder of the provided repository. Click **Save** once it’s been selected.
The contents of the code editor under **Code source** should have updated to show the code stored in the zip file.
### Configure environment variables
Next, you need to set the PlanetScale `DATABASE_URL` environment variable that you copied earlier. Select the **Configuration** tab, and click **Edit**.
You’ll be presented with a view to add or update environment variables. Click **Add environment variable** and the view will update with a row to add an environment variable. Set the **Key** field to **DATABASE_URL** and the **Value** to the connection string taken from the previous section. Click **Save** once finished.
Finally, test the function by selecting the **Test** tab, and then clicking the **Test** button.
An **Execution results** box will display above the **Test event** section. If the box is green, it likely means everything executed as expected. Click the dropdown next to **Details** to see the results of the query. Since the results of the query were logged out to the console, they will be displayed in the **Log output** section.
---
## File: docs/tutorials/connect-any-application.md
---
title: 'Connect any application to PlanetScale'
subtitle: 'Connect your PlanetScale database to any application using connection strings or the PlanetScale proxy'
date: '2022-08-01'
---
## Introduction
In this tutorial, you'll learn how to connect any application to your PlanetScale database.
If you're just getting started and still need to set up a database, we recommend starting with the [PlanetScale quick start guide](/docs/tutorials/planetscale-quick-start-guide) first. We also have language/framework-specific guides under "**Integration guides**" if you prefer a more detailed walk-through.
PlanetScale uses [database branches](/docs/concepts/branching) to create a development-friendly workflow. Your database is initially created with a default branch, `main`, which is meant to serve as a development branch before promoting it to production.
While _developing_ your application, you'll need to connect to a _development_ branch. Your production application, however, should be connected to your production database branch. Check out our [Branching guide](/docs/concepts/branching) for more information about the branching workflow.
There are two ways to connect your app to PlanetScale. Both are covered below.
## Option 1: Connect with username and password (Recommended)
This section will show you how to create a username and password for your branch and use those credentials to connect to your database. This is the recommended way to connect.
There are two ways to generate a new username and password for your branch:
- In the PlanetScale dashboard
- With the PlanetScale CLI
### Generate credentials in the PlanetScale dashboard
1. Click on the branch you want to connect to.
2. Click "**Connect**".
3. Select the applicable language from the "**Connect with**" dropdown or choose "General".
4. If the password isn't visible, click "New password".
5. Copy the credentials.
6. Paste them in your application's MySQL configuration file (often just a `.env` file). The layout and name of this file will vary depending on the application language, but it may look something like this:
```bash
DATABASE=
USERNAME=
HOST=
PASSWORD=
SSL= // more information about this in next step
```
Check out our language integration guides in the side navigation for more explicit instructions.
7. To ensure a secure connection, you must validate the server-side certificate from PlanetScale. This configuration depends on your application, but often it just means adding a line to your `.env` file similar to this:
```bash
MYSQL_ATTR_SSL_CA=/etc/ssl/cert.pem
```
The path to the certificate depends on your system. The above example shows the path for macOS, but you can find others in our [Secure connections documentation](/docs/concepts/secure-connections#ca-root-configuration).
Again, the variable name here, `MYSQL_ATTR_SSL_CA`, is just an example. The actual name and location for it will depend on the application.
If you're **unsure what to put here**, we recommend selecting your application's language from the dropdown in the PlanetScale dashboard (see step 3 above) and copying the credentials from there. This includes the necessary SSL configuration variables and shows what files they belong in. Additionally, we show you the correct certificate path by default based on your system.
### Generate credentials in the PlanetScale CLI
If you prefer working from the CLI, you can quickly spin up new credentials there. Make sure you have the [CLI set up](/docs/concepts/planetscale-environment-setup) first.
1. Run the following command in the CLI to create a new username and password for your branch.
```bash
pscale password create
```
{% callout %}
The `PASSWORD_NAME` value represents the name of the username and password being generated. You can have multiple credentials for a branch, so this gives you a way to categorize them. To manage your passwords in the dashboard, go to your database overview page, click "Settings", and then click "Passwords".
{% /callout %}
2. Take note of the values returned. You won't be able to see this password again.
```
Password production-password was successfully created.
Please save the values below as they will not be shown again.
NAME USERNAME ACCESS HOST URL ROLE PASSWORD
--------------------- ------------- --------------------------------- ------------------ --------------------------------
production-password xxxxxxxxxx xxxxxxxxxx.us-east-2.psdb.cloud Can Read & Write pscale_pw_xxxxxx_xxxxxxxxxxxxx
```
3. Paste the values from the console output into your application's MySQL configuration file. The layout and name of this file will vary depending on the application language, but it may look something like this:
```bash
DATABASE=
USERNAME=
HOST=
PASSWORD=
SSL= // This is covered in the next step
```
4. To ensure a secure connection, you must validate the server-side certificate from PlanetScale. This configuration depends on your application, but often it just means adding a line to your `.env` file similar to this:
```bash
MYSQL_ATTR_SSL_CA=/etc/ssl/cert.pem
```
The path to the certificate depends on your system. The above example shows the path for macOS, but you can find others in our [Secure connections documentation](/docs/concepts/secure-connections#ca-root-configuration).
Again, the variable name here, `MYSQL_ATTR_SSL_CA`, is just an example. The actual name and location for it will depend on the application.
If you're **unsure what to put here**, we recommend selecting your application's language from the dropdown in the PlanetScale dashboard (see step 3 from the previous section) and copying the credentials from there. This includes the necessary SSL configuration variables and shows what files they belong in. Additionally, we show you the correct certificate path by default based on your system.
## Option 2: Connect using the PlanetScale proxy
Another way to connect your application to your PlanetScale database _during development_ is using the PlanetScale proxy. You won't have to fiddle with configuring any credential details, as that's handled by PlanetScale. It's as simple as a single CLI command.
You'll use the CLI to establish a secure connection to PlanetScale. It will listen on a local port that your application can connect to. The main benefit of this method is you won't have to generate and remember multiple passwords every time you're creating or switching to a new branch.
1. Make sure you have [the CLI set up](/docs/concepts/planetscale-environment-setup), and then run the following command:
```bash
pscale connect
```
This establishes a secure connection and opens a port on your local machine that you can use to connect to any MySQL client.
2. Take note of the address it returns to you. By default it is `127.0.0.1:3306`. The CLI will use a different port if `3306` is unavailable.
3. In your application's MySQL configuration file, use the following to connect:
```bash
DATABASE=
HOST=127.0.0.1
PORT=3306 // use the value that was returned in the console
```
Your application should now be connected to the specified PlanetScale database branch!
## What's next?
Once your application is connected to a development database branch, you can make schema changes in an isolated development environment without worrying about affecting production. Additionally, the PlanetScale workflow allows you to make [non-blocking schema changes](/docs/concepts/nonblocking-schema-changes) without locking or causing downtime for production databases.
### PlanetScale workflow
Here's the general workflow that you'll go through to get schema changes from development to production:
1. Follow this guide to connect to a development branch.
2. Modify your schema as needed.
3. Test them locally or in your staging environment.
4. Once satisfied and ready to deploy your changes to production, [create a deploy request](/docs/concepts/deploy-requests).
5. You or your team can review and approve the schema changes.
6. Deploy your deploy request to production.
7. Bonus: If you realize you made a mistake, you can click "Revert changes" to [undo a schema change](/docs/concepts/deploy-requests#revert-a-schema-change).
Note: you must already have [a production branch](/docs/concepts/branching#promote-a-branch-to-production) in place to create a deploy request.
---
## File: docs/tutorials/connect-django-app.md
---
title: 'Connect a Django application to PlanetScale'
subtitle: 'Spin up a PlanetScale MySQL serverless database in seconds and connect to a Django application'
date: '2022-12-06'
---
## Introduction
In this tutorial, you'll learn how to connect a Django application to a PlanetScale MySQL database using a pre-built Django application.
{% callout type="tip" %}
Already have a Django application and just want to connect to PlanetScale? Check out the [Django quick connect repo](https://github.com/planetscale/connection-examples/tree/main/python).
{% /callout %}
## Prerequisites
- Python — This tutorial uses `v3.6`
- A [free PlanetScale account](https://auth.planetscale.com/sign-up)
- (Optional) [PlanetScale CLI](https://github.com/planetscale/cli) — This isn't required, but it can make setup much faster
## Set up the Django application
This guide integrates a simple Django application with PlanetScale. The application has one endpoint that displays a list of products and categories pulled from the database. If you have an existing application, you can also use that.
1. Clone the starter Django application and switch into the project folder:
```bash
git clone https://github.com/planetscale/django-example.git
cd django-example
```
2. Start the virtual environment:
```bash
python3 -m venv env
source env/bin/activate
```
For Windows, use `env/Scripts/activate`.
3. Install the required packages:
```bash
pip install -r ./requirements.txt
```
## Set up the database
Next, you need to set up your PlanetScale database and connect to it in the Django application.
You can create a database either in the [PlanetScale dashboard](https://app.planetscale.com) or from the PlanetScale CLI. This guide will use the CLI, but you can follow the database setup instructions in the [PlanetScale quickstart guide](/docs/tutorials/planetscale-quick-start-guide#getting-started-planetscale-dashboard) if you prefer the dashboard.
Authenticate the CLI with the following command:
```bash
pscale auth login
```
Create a new database with a default `main` branch with the following command:
```bash
pscale database create --region
```
This tutorial uses `django_example` for `DATABASE_NAME`, but you can use any name with lowercase, alphanumeric characters, or underscores. You can also use dashes, but we don't recommend them, as they may need to be escaped in some instances.
For `REGION_SLUG`, choose a region closest to you from the [available regions](/docs/concepts/regions#available-regions) or leave it blank.
That's it! Your database is ready to use. Next, let's connect it to the Django application and then add some data.
## Connect to the Django application
There are **two ways to connect** your Django application to PlanetScale:
- With an auto-generated username and password
- Using the PlanetScale proxy with the CLI
Both options are covered below.
### Option 1: Connect with username and password (Recommended)
1. Create a username and password with the PlanetScale CLI by running:
```bash
pscale password create
```
{% callout %}
The `PASSWORD_NAME` value represents the name of the username and password being generated. You can have multiple credentials for a branch, so this gives you a way to categorize them. To manage your passwords in the dashboard, go to your database overview page, click "Settings", and then click "Passwords".
{% /callout %}
You can also get these exact values to copy/paste from your [PlanetScale dashboard](https://app.planetscale.com). In the dashboard, click on the database > "**Connect**" > "**Connect with**" language dropdown > "**Django**". If the password is blurred, click "**New password**".
Take note of the values returned to you, as you won't be able to see this password again.
1. Open the .env file in your Django app, find the database connection section, and fill it in as follows:
```bash
DB_HOST=
DB_PORT=3306
DB_NAME=
DB_USER=
DB_PASSWORD=
MYSQL_ATTR_SSL_CA=/etc/ssl/cert.pem
```
The value for `MYSQL_ATTR_SSL_CA` may differ [depending on your operating system](/docs/concepts/secure-connections#ca-root-configuration).
3. Next, in the `mysite/settings.py` file, scroll down and look for the `DATABASES` object. Replace it with the following:
```python
DATABASES = {
'default': {
'ENGINE': 'django_psdb_engine',
'NAME': os.environ.get('DB_NAME'),
'HOST': os.environ.get('DB_HOST'),
'PORT': os.environ.get('DB_PORT'),
'USER': os.environ.get('DB_USER'),
'PASSWORD': os.environ.get('DB_PASSWORD'),
'OPTIONS': {'ssl': {'ca': os.environ.get('MYSQL_ATTR_SSL_CA')}}
}
}
```
### Option 2: Connect with PlanetScale proxy
To connect with the PlanetScale proxy, you'll need the [PlanetScale CLI](https://github.com/planetscale/cli).
1. Open a connection by running the following:
```bash
pscale connect
```
If you're following this guide exactly and haven't created any new branches, you'll use the default branch, `main`, for `BRANCH_NAME`.
2. A secure connection to your database will be established and you'll see a local address you can use to connect to your application.
3. Open the `.env` file in your Django app and update it as follows:
```bash
DB_HOST=127.0.0.1
DB_PORT=3306
DB_NAME=
```
The connection uses port `3306` by default, but if that's being used, it will pick a random port. Make sure you paste in whatever port is returned in the terminal.
## Optional — Bring in PlanetScale custom database wrapper
This next step is only necessary if you're using your own application to go through this guide. If you cloned the sample app, this already exists in the repo.
Because PlanetScale doesn't support foreign key constraints, you need to pull in the PlanetScale database wrapper for Django to disable foreign key syntax in the Django migrations.
1. Run the following to pull it in:
```bash
git clone https://github.com/planetscale/django_psdb_engine.git
```
2. In your `settings.py` file, add `django_psdb_engine` as the database engine.
```python
DATABASES = {
'default': {
'ENGINE': 'django_psdb_engine',
}
}
```
## Run migrations and seeder
Now that you're connected, let's add some data to see everything in action.
You can find the migrations file in `mysite/store/migrations/0002_auto_20220919_0058.py` that references the `Category` and `Product` models to create the schema. It also contains seed data to create two products and two categories. Run this migration with:
```bash
python manage.py migrate
```
This will also run the default Django migrations.
## Display the data
Finally, let's display the data to confirm that everything worked correctly.
This Django starter application has a pre-built endpoint, `/products`, that will grab and display all of the product data.
To view the data, start the server:
```bash
python manage.py runserver
```
Then go to [`localhost:8000/products`](http://localhost:8000/products) and you'll see a list of the data from the products table.
## Add data manually
If you want to continue playing around with adding data on the fly, you have a few options:
- PlanetScale CLI shell
- PlanetScale dashboard console
- Your favorite MySQL client (for a list of tested MySQL clients, review our article on [how to connect MySQL GUI applications](/docs/tutorials/connect-mysql-gui))
The first two options are covered below.
### Add data with PlanetScale CLI
You can use the PlanetScale CLI to open a MySQL shell to interact with your database.
You may need to [install the MySQL command line client](/docs/concepts/planetscale-environment-setup) if you haven't already.
Run the following command in your terminal:
```bash
pscale shell
```
This will open up a MySQL shell connected to the specified database and branch.
{% callout %}
A branch, `main`, was automatically created when you created your database, so you can use that for `BRANCH_NAME`.
{% /callout %}
Add a record to the `store_product` table:
```sql
INSERT INTO `store_product` (name, description, image, category_id)
VALUES ('Product 3', 'Product 3 description', 'https://via.placeholder.com/300.png?text=Product1', 1);
```
The value `id` will be filled with a default value.
Type `exit` to exit the shell.
Refresh the Django homepage to see the new record. You can also verify it was added in the PlanetScale CLI MySQL shell with:
```sql
select * from store_product;
```
### Add data with PlanetScale dashboard console
If you don't care to install MySQL client or the PlanetScale CLI, another quick option using the MySQL console built into the PlanetScale dashboard.
1. Go to your [PlanetScale dashboard](https://app.planetscale.com) and select your Django database.
2. Click on the "**Branches** and select the `main` branch.
3. Click on "**Console**"
4. Add a new record to the `store_product` table with:
```sql
INSERT INTO `store_product` (name, description, image, category_id)
VALUES ('Product 3', 'Product 3 description', 'https://via.placeholder.com/300.png?text=Product1', 1);
```
5. You can confirm that it was added by running:
```sql
select * from store_product;
```
You can also head to the [`/products`](http://localhost:8000/products) endpoint in your Django application to see the new data.
## Disabling foreign key constraints in Django
PlanetScale [does not support foreign key constraints](/docs/learn/operating-without-foreign-key-constraints). You can disable foreign key constraint checks at the model level in Django, but if you're running the default migrations, you'll need to turn them off globally.
The [PlanetScale custom database backend](https://github.com/planetscale/django_psdb_engine) manages this, but if you want to do it manually in each model. For example, in the `models.py` file for the example in this document, we define the foreign key on the `category` table with the following:
```python
category = models.ForeignKey(Category, on_delete=models.DO_NOTHING, db_constraint=False)
```
This isn't necessary to do in every model if you're pulling in the `django_psdb_engine` because it overrides the setting globally anyway, but this will work if you want to do it per model.
## What's next?
Once you're done with development, you can [promote your `main` branch to production](/docs/concepts/branching#promote-a-branch-to-production) to get a highly available branch protected by direct schema changes.
Learn more about how PlanetScale allows you to make [non-blocking schema changes](/docs/concepts/nonblocking-schema-changes) to your database tables without locking or causing downtime for production databases.
---
## File: docs/tutorials/connect-go-app.md
---
title: Connect a Go application to PlanetScale
subtitle: Learn how to use Go with PlanetScale by exploring a demo Go API built with Gin.
date: '2022-10-11'
---
{% vimeo src="https://player.vimeo.com/video/759188218" caption="Connect to PlanetScale with Go" /%}
## Introduction
In this guide, you’ll learn how to connect to a PlanetScale MySQL database with Go by exploring a sample API built using the Gin routing framework.
**Prerequisites:**
- [Go](https://go.dev/doc/install)
- [A PlanetScale account](https://auth.planetscale.com/sign-up)
- [VS Code](https://code.visualstudio.com/download) (optional)
- The [VS Code Rest Client plugin](https://marketplace.visualstudio.com/items?itemName=humao.rest-client) (optional)
{% callout type="tip" %}
Already have a Go application and just want to connect to PlanetScale? Check out the [Go quick connect repo](https://github.com/planetscale/connection-examples/tree/main/go).
{% /callout %}
## Create the database
Start in PlanetScale by creating a new database named `products_db`.
Once the database has finished initializing, head to **"Branches"** > **"main"**.
Click on **"Console"** to open the web console.
Run the following two commands to create a sample table and insert some data:
```sql
CREATE TABLE `products` (
`id` int PRIMARY KEY AUTO_INCREMENT,
`name` varchar(100) NOT NULL,
`price` int NOT NULL
);
INSERT INTO `products` (name, price) VALUES
('Cyberfreak 2076', 40),
('Destination 2: Shining Decline', 20),
('Edge Properties 3', 15);
```
Finally, head to the **"Overview"** tab and click **"Connect"**.
Change the **"Connect with"** dropdown to **Go** and copy the contents of the **.env** tab, as you’ll need it for the next section.
## Run the demo project
Start by opening a terminal on your workstation and clone the sample repository provided.
```bash
git clone https://github.com/planetscale/golang-example-gin.git
```
Open the project in VS Code and add a new file in the root of the project named `.env`, Populate the file with the contents taken from the Connect modal in the previous section.
```sql
DSN=****************:************@tcp(us-east.connect.psdb.cloud)/products_db?tls=true
```
Now open an integrated terminal in VS Code and run the project using the following commands:
```bash
go mod tidy
go run .
```
The terminal should update with the following output.
## Exploring the code
Now that the project is running, let’s explore the code to see how everything works. All of the code is stored in `main.go`, with each of the core SQL operations mapped by HTTP method in the `main` function:
| HTTP Method Name | Query Type |
| ---------------- | ---------- |
| get | SELECT |
| post | INSERT |
| put | UPDATE |
| delete | DELETE |
```go
func main() {
// Load in the `.env` file
err := godotenv.Load()
if err != nil {
log.Fatal("failed to load env", err)
}
// Open a connection to the database
db, err = sql.Open("mysql", os.Getenv("DSN"))
if err != nil {
log.Fatal("failed to open db connection", err)
}
// Build router & define routes
router := gin.Default()
router.GET("/products", GetProducts)
router.GET("/products/:productId", GetSingleProduct)
router.POST("/products", CreateProduct)
router.PUT("/products/:productId", UpdateProduct)
router.DELETE("/products/:productId", DeleteProduct)
// Run the router
router.Run()
}
```
Open the `tests.http` file, which contains HTTP requests that can be sent to test the API. Running the `get {{hostname}}/products` test is the equivalent of running `SELECT * FROM products` in SQL and returning the results as JSON.
{% callout type="warning" %}
If you do not wish to use VS Code with the Rest Client plugin, you may use `tests.http` as a reference for your preferred IDE and API testing software.
{% /callout %}
This is the `GetProducts` function defined in `main.go`. Notice how the `query` variable is the `SELECT` statement, which is passed into `db.Query` before being scanned into a slice of `Product` structs.
```go
func GetProducts(c *gin.Context) {
query := "SELECT * FROM products"
res, err := db.Query(query)
defer res.Close()
if err != nil {
log.Fatal("(GetProducts) db.Query", err)
}
products := []Product{}
for res.Next() {
var product Product
err := res.Scan(&product.Id, &product.Name, &product.Price)
if err != nil {
log.Fatal("(GetProducts) res.Scan", err)
}
products = append(products, product)
}
c.JSON(http.StatusOK, products)
}
```
To pass parameters into queries, you may use a `?` as a placeholder for the parameter. For example, `GetSingleProduct` uses a query with a `WHERE` clause that is passed into the `db.QueryRow` function along with the query string.
```go
func GetSingleProduct(c *gin.Context) {
productId := c.Param("productId")
productId = strings.ReplaceAll(productId, "/", "")
productIdInt, err := strconv.Atoi(productId)
if err != nil {
log.Fatal("(GetSingleProduct) strconv.Atoi", err)
}
var product Product
// `?` is a placeholder for the parameter
query := `SELECT * FROM products WHERE id = ?`
// `productIdInt` is passed in with the query
err = db.QueryRow(query, productIdInt).Scan(&product.Id, &product.Name, &product.Price)
if err != nil {
log.Fatal("(GetSingleProduct) db.Exec", err)
}
c.JSON(http.StatusOK, product)
}
```
Parameters in queries are populated in the order they are passed into the respective `db` function, as demonstrated in `CreateProduct`.
```go
func CreateProduct(c *gin.Context) {
var newProduct Product
err := c.BindJSON(&newProduct)
if err != nil {
log.Fatal("(CreateProduct) c.BindJSON", err)
}
// This query has multiple `?` parameter placeholders
query := `INSERT INTO products (name, price) VALUES (?, ?)`
// The `Exec` function takes in a query, as well as the values for
// the parameters in the order they are defined
res, err := db.Exec(query, newProduct.Name, newProduct.Price)
if err != nil {
log.Fatal("(CreateProduct) db.Exec", err)
}
newProduct.Id, err = res.LastInsertId()
if err != nil {
log.Fatal("(CreateProduct) res.LastInsertId", err)
}
c.JSON(http.StatusOK, newProduct)
}
```
---
## File: docs/tutorials/connect-go-gorm-app.md
---
title: 'Connect a Go application using GORM to PlanetScale'
subtitle: 'Spin up a PlanetScale MySQL serverless database in seconds and connect to a Go application using GORM'
date: '2022-12-06'
---
## Introduction
In this tutorial, you'll learn how to connect a Go application to a PlanetScale MySQL database using a sample Go starter app with GORM.
{% callout type="tip" %}
Already have a Go application and just want to connect to PlanetScale? Check out the [Go quick connect
repo](https://github.com/planetscale/connection-examples/tree/main/go).
{% /callout %}
## Prerequisites
- [Go](https://go.dev/doc/install)
- A [free PlanetScale account](https://auth.planetscale.com/sign-up)
- [PlanetScale CLI](https://github.com/planetscale/cli) — You can also follow this tutorial in the PlanetScale admin dashboard, but the CLI will make setup quicker.
## Set up the Go app
This guide will integrate [a simple Go (Golang) app](https://github.com/planetscale/golang-example) with PlanetScale that will display a list of products stored in the database. If you have an existing application, you can also use that.
1. Clone the starter Go application:
```bash
git clone https://github.com/planetscale/golang-example.git
```
2. Enter into the folder:
```bash
cd golang-example
```
3. Copy the `.env.example` file into `.env`:
```bash
cp .env.example .env
```
## Set up the database
Next, you need to set up your PlanetScale database and connect to it in the Go application.
You can create a database in the [PlanetScale dashboard](https://app.planetscale.com) or from the PlanetScale CLI. This guide will use the CLI, but you can follow the database setup instructions in the [PlanetScale quickstart guide](/docs/tutorials/planetscale-quick-start-guide) if you prefer the dashboard.
1. Authenticate the CLI with the following command:
```bash
pscale auth login
```
2. Create a new database with a default `main` branch with the following command:
```bash
pscale database create --region
```
For `DATABASE_NAME`, you can use any name with lowercase, alphanumeric characters, or underscores. You can also use dashes, but we don't recommend them, as they may need to be escaped in some instances.
For `REGION_SLUG`, choose a region closest to you from the [available regions](/docs/concepts/regions#available-regions) or leave it blank.
That's it! Your database is ready to use. Next, let's connect it to the Go application and then add some data.
## Connect to the Go app
There are **two ways to connect** your Go app to PlanetScale:
- With an auto-generated username and password
- Using the PlanetScale proxy with the CLI
Both options are covered below.
### Option 1: Connect with username and password (Recommended)
1. Create a username and password with the PlanetScale CLI by running:
```bash
pscale password create
```
A default branch, `main`, is created when you create the database, so you can use that for `BRANCH_NAME`.
{% callout %}
The `PASSWORD_NAME` value represents the name of the username and password being generated. You can have multiple
credentials for a branch, so this gives you a way to categorize them. To manage your passwords in the dashboard, go to
your database overview page, click "Settings", and then click "Passwords".
{% /callout %}
Take note of the values returned to you, as you won't be able to see this password again.
2. Open the `.env` file in your Go app and update `DSN` as follows:
```bash
DSN=":@tcp()/?tls=true"
```
Fill in `USERNAME`, `PASSWORD`, `ACCESS HOST URL`, and `DATABASE_NAME` with the appropriate values from the CLI output above. Do not remove the parentheses around the access host URL.
You can also get these exact values to copy/paste from your PlanetScale dashboard. In the dashboard, click on the database > "**Connect**" > "**Connect with**" language dropdown > "**Go**".
### Option 2: Connect with the PlanetScale proxy
To connect with the PlanetScale proxy, you need the [PlanetScale CLI](https://github.com/planetscale/cli).
1. Open a connection by running the following:
```bash
pscale connect
```
If you're following this guide exactly and haven't created any branches, you can use the default branch, `main`.
2. A secure connection to your database will be established, and you'll see a local address you can use to connect to your application.
3. Open the `.env` file in your Go app and update it as follows:
```bash
DSN="mysql://root@tcp(127.0.0.1:)/"
```
The connection uses port `3306` by default, but if that's being used, it will pick a random port. Make sure you paste in whatever port is returned in the terminal. Fill in the database name as well.
## Run migrations and seeder
Now that you're connected let's add some data to see it in action. The sample application has an endpoint that you can use to run migrations to create your `categories` and `products` tables. It will seed your database with sample product and category data. You can find this in `main.go`.
Let's run those now.
1. First, start your Go app with:
```bash
go run .
```
2. Next, navigate to [`localhost:8080/seed`](http://localhost:8080/seed) to run the migrations and the seeder.
3. You can now see the products and categories:
- Get all products — [`localhost:8080/products`](http://localhost:8080/products)
- Get all categories — [`localhost:8080/categories`](http://localhost:8080/categories)
- Get a single product — [`localhost:8080/product/{id}`](http://localhost:8080/products/1)
- Get a single category — [`localhost:8080/category/{id}`](http://localhost:8080/categories/1)
### Foreign key constraints
If you're using GORM in your Go application, take note of this line in the `main.go` file of the Go starter application:
```go
// ...
DisableForeignKeyConstraintWhenMigrating: true,
// ...
```
PlanetScale does not support foreign key _constraints_, but we do support the use of relationships with foreign keys, as shown in this example. For more information, check out our [Operating without foreign key constraints](/docs/learn/operating-without-foreign-key-constraints) documentation.
## Add data manually
If you want to continue to play around with adding data on the fly, you have a few options:
- PlanetScale CLI shell
- PlanetScale dashboard console
- Your favorite MySQL client (for a list of tested MySQL clients, review our article on [how to connect MySQL GUI applications](/docs/tutorials/connect-mysql-gui))
The first two options are covered below.
### Add data with PlanetScale CLI
You can use the PlanetScale CLI to open a MySQL shell to interact with your database.
You may need to install the MySQL command line client if you haven't already.
1. Run the following command in your terminal:
```bash
pscale shell
```
This will open up a MySQL shell connected to the specified database and branch.
{% callout %}
A branch, `main`, was automatically created when you created your database, so you can use that for `BRANCH_NAME`.
{% /callout %}
2. Add a record to the `products` table:
```sql
INSERT INTO `products` (name, description, image, category_id)
VALUES ('Spaceship', 'Get ready for the trip of a lifetime', 'https://via.placeholder.com/300.png', 2);
```
The value `id` will be filled with a default value.
3. You can verify it was added in the PlanetScale CLI MySQL shell with:
```sql
SELECT * FROM products;
```
4. Type `exit` to exit the shell.
You can now navigated the [Go products page](http://localhost:8080/products) to see the new record.
### Add data with PlanetScale dashboard console
If you don't care to install MySQL client or the PlanetScale CLI, another quick option is using the MySQL console built into the PlanetScale dashboard.
1. Go to your [PlanetScale dashboard](https://app.planetscale.com) and select your Go database.
2. Click on the "**Branches** and select the `main` branch.
3. Click on "**Console**"
4. Add a new record to the `product` table with:
```sql
INSERT INTO `products` (name, description, image, category_id)
VALUES ('Spaceship', 'Get ready for the trip of a lifetime', 'https://via.placeholder.com/300.png', 2);
```
5. You can confirm that it was added by running:
```sql
SELECT * FROM products;
```
You can now refresh the [Go products page](http://localhost:8080/products) to see the new record.
## What's next?
Once you're done with development, you can [promote your `main` branch to production](/docs/concepts/branching#promote-a-branch-to-production) to get a highly available branch protected by direct schema changes.
When you're reading to make more schema changes, you'll [create a new branch](/docs/concepts/branching) off of your production branch. Branching your database creates an isolated copy of your production schema so that you can easily test schema changes in development. Once you're happy with the changes, you'll open a [deploy request](/docs/concepts/deploy-requests). This will generate a diff showing the changes that will be deployed, making it easy for your team to review.
Learn more about how PlanetScale allows you to make [non-blocking schema changes](/docs/concepts/nonblocking-schema-changes) to your database tables without locking or causing downtime for production databases.
---
## File: docs/tutorials/connect-laravel-app.md
---
title: 'Connect a Laravel application to PlanetScale'
subtitle: 'Spin up a PlanetScale MySQL serverless database in seconds and connect to a Laravel application'
className: 'ignore-img-borders'
date: '2022-12-06'
---
## Introduction
In this tutorial, you'll learn how to connect a Laravel application to a PlanetScale MySQL database using a sample Laravel starter app.
## Prerequisites
- [PHP](https://www.php.net/manual/en/install.php) — This tutorial uses `v8.1`
- [Composer](https://getcomposer.org/)
- A [free PlanetScale account](https://auth.planetscale.com/sign-up)
## Set up the Laravel app
This guide will integrate [a simple Laravel 9 app](https://github.com/planetscale/laravel-example) with PlanetScale. The application will display a list of stars and what constellation each star is in. The sample repo contains migrations and seed data to create and populate the `constellations` and `stars` tables. If you have an existing application, you can also use that.
1. Clone the starter Laravel application:
```bash
git clone https://github.com/planetscale/laravel-example.git
```
2. Enter into the folder and install the dependencies:
```bash
cd laravel-example
composer install
```
You may need to run `composer update` if you haven't updated in a while.
3. Copy the `.env.example` file into `.env`:
```bash
cp .env.example .env
```
4. Start the application:
```bash
php artisan serve
```
You can view the application at [http://localhost:8000](http://localhost:8000).
## Set up the database
Next, you need to set up your PlanetScale database and connect to it in the Laravel application.
If this is your first time in the dashboard, you'll be prompted to go through a database creation walkthrough where you'll create a new database. Otherwise, click "**New database**" > "**Create new database**".
- **Name** — You can use any name with lowercase, alphanumeric characters, or underscores. We also permit dashes, but don't recommend them, as they may need to be escaped in some instances.
- **Region** — Choose the [region](/docs/concepts/regions#available-regions) closest to you or your application. It's important to note if you intend to make this branch a production branch, you will not be able to change the region later, so choose the region with this in mind.
Finally, click "**Create database**".
{% callout %}
If you have an existing cloud-hosted database, you can also choose the "**Import**" option to import your database to PlanetScale using our Import tool. If you go this route, we recommend using our [Database Imports documentation](/docs/imports/database-imports).
{% /callout %}
A [development branch](/docs/concepts/branching), `main`, is automatically created when you create your database. You can use this branch to develop on, and once you're happy with any schema changes, you can promote it to production, where it becomes a highly available, protected database that you can connect your production application to.
That's it! Your database is ready to use. Next, let's connect it to the Laravel application and then add some data.
## Connect to the Laravel app
There are **two ways to connect** to PlanetScale:
- With an auto-generated username and password
- Using the PlanetScale proxy with the CLI
Both options are covered below.
### Option 1: Connect with username and password (Recommended)
Next, you need to generate a database username and password so that you can use it to connect to your application.
In your PlanetScale dashboard, select your database, click "**Connect**", and select "**Laravel**" from the "**Connect with**" dropdown.
As long as you're an organization administrator, this will generate a username and password that has administrator privileges to the database.
{% callout type="tip" %}
If the password value is blurred, you need to click "**New password**" to generate a new one.
{% /callout %}
Copy the contents of the `.env` tab and paste them into your own `.env` file in your Laravel application. The structure will look like this:
```bash
DB_CONNECTION=mysql
DB_HOST=
DB_PORT=3306
DB_DATABASE=
DB_USERNAME=
DB_PASSWORD=
MYSQL_ATTR_SSL_CA=/etc/ssl/cert.pem
```
The `MYSQL_ATTR_SSL_CA` value is platform dependent. Please see our documentation around [how to connect to PlanetScale securely](/docs/concepts/secure-connections#ca-root-configuration) for the configuration for the platform you're using.
Refresh your Laravel homepage and you should see the message that you're connected to your database!
### Option 2: Connect with the PlanetScale proxy
To connect with the PlanetScale proxy, you need to install and use the [PlanetScale CLI](https://github.com/planetscale/cli).
1. Open a connection by running the following:
```bash
pscale connect
```
If you're following this guide exactly and haven't created any branches, you can use the default branch, `main`.
2. A secure connection to your database will be established and you'll see a local address you can use to connect to your application.
3. Open the `.env` file in your Laravel app and update it as follows:
```bash
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306 # Get this from the output of the previous step
DB_DATABASE=
DB_USERNAME=
DB_PASSWORD=
```
The connection uses port `3306` by default, but if that's being used, it will pick a random port. Make sure you paste in whatever port is returned in the terminal. You can leave `DB_USERNAME` and `DB_PASSWORD` blank.
Refresh your Laravel homepage and you should see the message that you're connected to your database!
## Run migrations and seeder
Now that you're connected, let's add some data to see it in action. The sample application comes with two migration files:
- `database/migrations/2021_12_20_194637_create_stars_table.php` — Creates a `stars` table
- `database/migrations/2022_07_26_190656_create_constellations_table.php` — Creates a `constellations` table
{% callout %}
PlanetScale does not support foreign key _constraints_, but we do support the use of relationships with foreign keys, as shown in the Stars migration file in this example.
You can use the [`foreignId()` method](https://laravel.com/docs/migrations#foreign-key-constraints) to create a relationship between the `constellations` and `stars` tables, but you cannot enforce referential integrity with the `constrained()` method.
For more information, check out our [Operating without foreign key constraints](/docs/learn/operating-without-foreign-key-constraints) documentation.
{% /callout %}
There are also two seeders, `database/seeders/ConstellationSeeder.php` and `database/seeders/StarSeeder.php`, that will add two rows to the each table. Let's run those now.
1. Make sure your database connection has been established. You'll see the message "You are connected to your_database_name" on the [Laravel app homepage](http://localhost:8000/) if everything is configured properly.
2. In your terminal in the root of the Laravel project, run the following to run the migration:
```bash
php artisan migrate
```
You should get a message that the migration table was successfully created.
3. Next, seed the database by running:
```bash
php artisan db:seed
```
You should get the message "Database seeding completed successfully".
4. Refresh your Laravel homepage and you'll see a list of stars and their constellations printed out.
The `resources/views/home.blade.php` file pulls this data from the `stars` table with the help of the `app/Http/Controllers/StarController.php` file.
## Add data manually
If you want to continue to play around with adding data on the fly, you have a few options:
- PlanetScale dashboard console
- [Laravel Tinker](https://laravel.com/docs/9.x/artisan#tinker)
- [PlanetScale CLI shell](/docs/reference/shell)
- Your favorite MySQL client (for a list of tested MySQL clients, review our article on [how to connect MySQL GUI applications](/docs/tutorials/connect-mysql-gui))
The first two options are covered below.
### Add data in PlanetScale dashboard console
PlanetScale has a [built-in console](/docs/concepts/web-console) where you can run MySQL commands against your branches. To access it, click "**Branches**" > your development branch > "**Console**".
From here, you can run MySQL queries and DDL against your database branch.
1. Add a record to the `constellations` table:
```sql
INSERT INTO `constellations` (name)
VALUES ('Kaus Media');
```
2. Add a record to the `stars` table:
```sql
INSERT INTO `stars` (name, constellation_id)
VALUES ('Sagittarius', 3);
```
3. Refresh the Laravel homepage to see the new record. You can also verify it was added in the console with:
```sql
SELECT * FROM stars;
```
### Add data with Laravel Tinker
Laravel comes with a powerful tool called [Tinker](https://laravel.com/docs/9.x/artisan#tinker) that lets you interact with your database from the command line. Let's add some data with it.
1. In your terminal, run the following command:
```bash
php artisan tinker
```
2. Insert a new record into the `constellations` table with:
```php
DB::table('constellations')->insert(['name'=>'Kaus Media']);
```
2. Insert a new record into the `stars` table with:
```php
DB::table('stars')->insert(['name'=>'Sagitarrius', 'constellation'=>3]);
```
3. Refresh your Laravel application homepage to see your new data. You can also run the following command in Tinker to see all records in the `stars` table.
```php
App\Models\Star::all();
```
4. Type `exit` to exit Tinker.
## What's next?
Once you're done with development, you can [promote your `main` branch to production](/docs/concepts/branching#promote-a-branch-to-production) to get a highly available branch protected by direct schema changes.
To learn more about PlanetScale, take a look at the following resources:
- [PlanetScale workflow](/docs/concepts/planetscale-workflow) — Quick overview of the PlanetScale workflow: branching, non-blocking schema changes, deploy requests, and reverting a schema change.
- [PlanetScale branching](/docs/concepts/branching) — Learn how to utilize branching to ship schema changes with no locking or downtime.
- [PlanetScale CLI](/docs/reference/planetscale-cli) — Power up your workflow with the PlanetScale CLI. Every single action you just performed in this quickstart (and much more) can also be done with the CLI.
---
## File: docs/tutorials/connect-mysql-gui.md
---
title: 'Connect a MySQL GUI to PlanetScale'
subtitle: 'Connect to your PlanetScale database using any MySQL GUI application'
date: '2022-12-06'
---
## Introduction
In this tutorial, you'll learn how to connect to a PlanetScale database using a MySQL GUI. While this tutorial uses Sequel Ace as a demonstration, many applications that connect to MySQL databases will support connecting to and querying a PlanetScale database as long as the applicaton supports connecting over SSL.
## Gather the credentials
To connect to a PlanetScale database, you'll need four pieces of information:
- The database name
- Host name
- Username
- Password
The easiest way to gather this information is by accessing the branch of the database you wish to connect to and selecting the **"Connect"** button from the **"Overview"** tab.
In the **Connect** modal, select **"General"** under the **Connect with** options. This will display the connection details as a list instead of a language or framework-specific connection string.
{% callout %}
As a security best practice, passwords are only displayed when they are created. If you do not know the password, you may generate a new credential set by clicking the **"New password"** button in the **Connect** modal.
{% /callout %}
## Connect to the database
In the application you are using, enter the access information you gathered in the previous step into the appropriate fields. Make sure to check **"Require SSL"** as SSL is required to connect to a PlanetScale database. Click **"Connect"** once you are finished.
If the connection is successful, you should be able to query your database and perform other [supported operations](/docs/reference/mysql-compatibility).
## Caveats
While many standard MySQL statements are supported, there are a few caveats worth calling out:
1. Each branch of a PlanetScale database is considered an isolated MySQL database. You'll need separate connection details per branch.
2. Production branches do not support DDL, so operations that modify the schema of your database or not supported. However, DDL is supported on non-production branches.
3. Creating new databases is not supported using any GUI tool.
## Tested GUIs
The following MySQL GUI applications have been tested and confirmed to work with PlanetScale databases:
- [Sequel Ace](https://sequel-ace.com/)
- [TablePlus](https://tableplus.com/)
- [MySQL Workbench](https://www.mysql.com/products/workbench/)
- [JetBrains DataGrip](/blog/using-planetscale-with-jetbrains-datagrip-mysql-gui)