diff --git a/v3-docs/docs/.vitepress/config.mts b/v3-docs/docs/.vitepress/config.mts index 5680608b44..99323cdea6 100644 --- a/v3-docs/docs/.vitepress/config.mts +++ b/v3-docs/docs/.vitepress/config.mts @@ -40,6 +40,10 @@ export default defineConfig({ text: "Meteor + Vue + vue-meteor-tracker", link: "/tutorials/vue/meteorjs3-vue3-vue-meteor-tracker", }, + { + text: "Meteor.js 3 + Solid", + link: "/tutorials/solid/index", + }, { link: "/tutorials/application-structure/index", text: "Application structure", @@ -472,6 +476,10 @@ export default defineConfig({ link: "/tutorials/vue/meteorjs3-vue3-vue-meteor-tracker", text: "Meteor + Vue + vue-meteor-tracker", }, + { + text: "Meteor.js 3 + Solid", + link: "/tutorials/solid/index", + }, { link: "/tutorials/application-structure/index", text: "Application structure", diff --git a/v3-docs/docs/tutorials/solid/1.creating-the-app.md b/v3-docs/docs/tutorials/solid/1.creating-the-app.md new file mode 100644 index 0000000000..8ff1fce41f --- /dev/null +++ b/v3-docs/docs/tutorials/solid/1.creating-the-app.md @@ -0,0 +1,200 @@ +## 1: Creating the app + +### 1.1: Install Meteor + +First, we need to install Meteor by following this [installation guide](https://docs.meteor.com/about/install.html). + +### 1.2: Create Meteor Project + +The easiest way to setup Meteor with Solid is by using the command `meteor create` with the option `--solid` and your project name: + +```shell +meteor create --solid simple-todos-solid +``` + +Meteor will create all the necessary files for you. + +The files located in the `client` directory are setting up your client side (web), you can see for example `client/main.html` where Meteor is rendering your App main component into the HTML. + +Also, check the `server` directory where Meteor is setting up the server side (Node.js), you can see the `server/main.js` which would be a good place to initialize your MongoDB database with some data. You don't need to install MongoDB as Meteor provides an embedded version of it ready for you to use. + +You can now run your Meteor app using: + +```shell +meteor +``` + +Don't worry, Meteor will keep your app in sync with all your changes from now on. + +Take a quick look at all the files created by Meteor, you don't need to understand them now but it's good to know where they are. + +Your Solid code will be located inside the `imports/ui` directory, and the `App.jsx` file will be the root component of your Solid To-do app. + +### 1.3: Create Tasks + +To start working on our todo list app, let’s replace the code of the default starter app with the code below. From there, we’ll talk about what it does. + +First, let’s simplify our HTML entry point like so: + +::: code-group + +```html [client/main.html] +
+
+
+In Solid with Meteor, your main entry point is `client/main.js`, which imports `imports/ui/main.jsx`
+to render your root Solid component `App.jsx` to a target element in the HTML like `` using Solid's `render` function.
+
+Solid components are defined in `.jsx` files using JSX syntax, which can include JavaScript logic, imports, and reactive primitives. The JSX markup can use Solid's control flow components, such as `
+
+Click on it and then select the phone that you want to simulate and in the top nav bar.
+
+> You can also check your app in your personal cellphone. To do so, connect to your App using your local IP in the navigation browser of your mobile browser.
+>
+> This command should print your local IP for you on Unix systems
+> `ifconfig | grep "inet " | grep -Fv 127.0.0.1 | awk '{print $2}'`
+>
+> On Microsoft Windows try this in a command prompt
+> `ipconfig | findstr "IPv4 Address"`
+
+You should see the following:
+
+
+
+As you can see, everything is small, as we are not adjusting the view port for mobile devices. You can fix this and other similar issues by adding these lines to your `client/main.html` file, inside the `head` tag, after the `title`.
+
+::: code-group
+
+```html [client/main.html]
+
+
+
+
+### 1.7: Hot Module Replacement
+
+Meteor uses a package called [hot-module-replacement](https://docs.meteor.com/packages/hot-module-replacement) which is already added for you. This package updates the javascript modules in a running app that were modified during a rebuild. Reduces the feedback cycle while developing, so you can view and test changes quicker (it even updates the app before the build has finished). You are also not going to lose the state, your app code will be updated, and your state will be the same.
+
+By default, when using Solid with Meteor, reactivity is handled by integrating Solid's fine-grained signals and effects with Meteor's Tracker system. This allows real-time updates of the user's screen as data changes in the database without them having to manually refresh. You can achieve this using Tracker.autorun combined with Solid's createEffect or signals for seamless reactivity.
+
+> You can read more about packages [here](https://docs.meteor.com/packages/).
+
+You should also add the package [dev-error-overlay](https://atmospherejs.com/meteor/dev-error-overlay) at this point, so you can see the errors in your web browser.
+
+```shell
+meteor add dev-error-overlay
+```
+
+You can try to make some mistakes and then you are going to see the errors in the browser and not only in the console.
+
+In the next step we are going to work with our MongoDB database to be able to store our tasks.
diff --git a/v3-docs/docs/tutorials/solid/2.collections.md b/v3-docs/docs/tutorials/solid/2.collections.md
new file mode 100644
index 0000000000..8e7c6b1e3b
--- /dev/null
+++ b/v3-docs/docs/tutorials/solid/2.collections.md
@@ -0,0 +1,183 @@
+## 2: Collections
+
+Meteor already sets up MongoDB for you. In order to use our database, we need to create a _collection_, which is where we will store our _documents_, in our case our `tasks`.
+
+> You can read more about collections [here](https://v3-docs.meteor.com/api/collections.html).
+
+In this step we will implement all the necessary code to have a basic collection for our tasks up and running.
+
+### 2.1: Create Tasks Collection
+
+We can create a new collection to store our tasks by creating a new file at `imports/api/TasksCollection.js` which instantiates a new Mongo collection and exports it.
+
+::: code-group
+
+```js [imports/api/TasksCollection.js]
+import { Mongo } from "meteor/mongo";
+
+export const TasksCollection = new Mongo.Collection("tasks");
+```
+:::
+
+Notice that we stored the file in the `imports/api` directory, which is a place to store API-related code, like publications and methods. You can name this folder as you want, this is just a choice.
+
+If there is a `imports/api/links.js` file from the starter project, you can delete that now as we don't need it.
+
+> You can read more about app structure and imports/exports [here](http://guide.meteor.com/structure.html).
+
+### 2.2: Initialize Tasks Collection
+
+For our collection to work, you need to import it in the server so it sets some plumbing up.
+
+You can either use `import "/imports/api/TasksCollection"` or `import { TasksCollection } from "/imports/api/TasksCollection"` if you are going to use on the same file, but make sure it is imported.
+
+Now it is easy to check if there is data or not in our collection, otherwise, we can insert some sample data easily as well.
+
+You don't need to keep the old content of `server/main.js`.
+
+::: code-group
+
+```js [server/main.js]
+import { Meteor } from "meteor/meteor";
+import { TasksCollection } from "/imports/api/TasksCollection";
+
+const insertTask = async (taskText) =>
+ await TasksCollection.insertAsync({ text: taskText });
+
+Meteor.startup(async () => {
+ if (await TasksCollection.find().countAsync() === 0) {
+ [
+ "First Task",
+ "Second Task",
+ "Third Task",
+ "Fourth Task",
+ "Fifth Task",
+ "Sixth Task",
+ "Seventh Task",
+ ].forEach(insertTask);
+ }
+});
+```
+:::
+
+So you are importing the `TasksCollection` and adding a few tasks to it iterating over an array of strings and for each string calling a function to insert this string as our `text` field in our `task` document.
+
+### 2.3: Render Tasks Collection
+
+Now comes the fun part, you will render the tasks with Solid. That will be pretty simple.
+
+In your `App.jsx` file, import the `TasksCollection` and use Tracker to subscribe and fetch the tasks reactively:
+
+::: code-group
+
+```jsx [imports/ui/App.jsx]
+import { createSignal, For, Show } from "solid-js";
+import { Meteor } from "meteor/meteor";
+import { Tracker } from "meteor/tracker";
+import { TasksCollection } from "../api/TasksCollection";
+
+export const App = () => {
+ const subscription = Meteor.subscribe("tasks");
+ const [isReady, setIsReady] = createSignal(subscription.ready());
+ const [tasks, setTasks] = createSignal([]);
+
+ Tracker.autorun(async () => {
+ setIsReady(subscription.ready());
+ setTasks(await TasksCollection.find().fetchAsync());
+ });
+
+ return (
+
+
+You can change your data on MongoDB in the server and your app will react and re-render for you.
+
+You can connect to your MongoDB running `meteor mongo` in the terminal from your app folder or using a Mongo UI client, like [NoSQLBooster](https://nosqlbooster.com/downloads). Your embedded MongoDB is running in port `3001`.
+
+See how to connect:
+
+
+
+See your database:
+
+
+
+You can double-click your collection to see the documents stored on it:
+
+
+
+In the next step, we are going to create tasks using a form.
diff --git a/v3-docs/docs/tutorials/solid/3.forms-and-events.md b/v3-docs/docs/tutorials/solid/3.forms-and-events.md
new file mode 100644
index 0000000000..c6aef8a73e
--- /dev/null
+++ b/v3-docs/docs/tutorials/solid/3.forms-and-events.md
@@ -0,0 +1,248 @@
+## 3: Forms and Events
+
+All apps need to allow the user to perform some sort of interaction with the data that is stored. In our case, the first type of interaction is to insert new tasks. Without it, our To-Do app wouldn't be very helpful.
+
+One of the main ways in which a user can insert or edit data on a website is through forms. In most cases, it is a good idea to use the `
+
+
+
+
+
+In the next step, we are going to update your tasks state and provide a way for users to remove tasks.
diff --git a/v3-docs/docs/tutorials/solid/4.update-and-remove.md b/v3-docs/docs/tutorials/solid/4.update-and-remove.md
new file mode 100644
index 0000000000..e2d6ef43f7
--- /dev/null
+++ b/v3-docs/docs/tutorials/solid/4.update-and-remove.md
@@ -0,0 +1,216 @@
+## 4: Update and Remove
+
+Up until now, you have only inserted documents into our collection. Let's take a look at how you can update and remove them by interacting with the user interface.
+
+### 4.1: Add Checkbox
+
+First, you need to add a `checkbox` element to your `Task` component.
+
+Next, let’s create a new file for our `task` in `imports/ui/Task.jsx`, so we can start to separate the logic in our app.
+
+::: code-group
+
+```jsx [imports/ui/Task.jsx]
+import { Meteor } from "meteor/meteor";
+
+export const Task = (props) => {
+ const { task } = props;
+
+ const toggleChecked = async () => {
+ await Meteor.callAsync("tasks.toggleChecked", { _id: task._id, isChecked: task.isChecked });
+ };
+
+ return (
+
+
+If your computer is fast enough, it's possible that when it sets up the default tasks a few will have the same date. That will cause them to non-deterministically "jump around" in the UI as you toggle checkboxes and the UI reactively updates. To make it stable, you can add a secondary sort on the `_id` of the task:
+
+::: code-group
+
+```jsx [imports/ui/App.jsx]
+...
+
+Tracker.autorun(async () => {
+ setIsReady(subscription.ready());
+ setTasks(await TasksCollection.find({}, { sort: { createdAt: -1, _id: -1 } }).fetchAsync()); // [!code highlight]
+});
+
+...
+```
+:::
+
+
+### 4.3: Remove tasks
+
+You can remove tasks with just a few lines of code.
+
+First, add a button after the `label` in your `Task` component and a `deleteTask` function.
+
+::: code-group
+
+```jsx [imports/ui/Task.jsx]
+import { Meteor } from "meteor/meteor";
+
+export const Task = (props) => {
+ const { task } = props;
+
+ const toggleChecked = async () => {
+ await Meteor.callAsync("tasks.toggleChecked", { _id: task._id, isChecked: task.isChecked });
+ };
+
+ const deleteTask = async () => { // [!code highlight]
+ await Meteor.callAsync("tasks.delete", { _id: task._id }); // [!code highlight]
+ }; // [!code highlight]
+
+ return (
+
+
+### 4.4: Getting data in event handlers
+
+In a collection, every inserted document has a unique `_id` field that can refer to that specific document. Inside the component, the `task` prop provides access to the task object, including its `_id`
+and other fields like `isChecked` and `text`. We use these to call Meteor methods for updating or removing the specific task.
+
+In the next step, we are going to improve the look of your app using CSS with Flexbox.
+
diff --git a/v3-docs/docs/tutorials/solid/5.styles.md b/v3-docs/docs/tutorials/solid/5.styles.md
new file mode 100644
index 0000000000..d8e4542f11
--- /dev/null
+++ b/v3-docs/docs/tutorials/solid/5.styles.md
@@ -0,0 +1,231 @@
+## 5: Styles
+
+### 5.1: CSS
+
+Our user interface up until this point has looked quite ugly. Let's add some basic styling which will serve as the foundation for a more professional looking app.
+
+Replace the content of our `imports/ui/main.css` file with the one below, the idea is to have an app bar at the top, and a scrollable content including:
+
+- form to add new tasks;
+- list of tasks.
+
+::: code-group
+
+```css [imports/ui/main.css]
+body {
+ font-family: sans-serif;
+ background-color: #315481;
+ background-image: linear-gradient(to bottom, #315481, #918e82 100%);
+ background-attachment: fixed;
+
+ position: absolute;
+ top: 0;
+ bottom: 0;
+ left: 0;
+ right: 0;
+
+ padding: 0;
+ margin: 0;
+
+ font-size: 14px;
+}
+
+button {
+ font-weight: bold;
+ font-size: 1em;
+ border: none;
+ color: white;
+ box-shadow: 0 3px 3px rgba(34, 25, 25, 0.4);
+ padding: 5px;
+ cursor: pointer;
+}
+
+button:focus {
+ outline: 0;
+}
+
+.app {
+ display: flex;
+ flex-direction: column;
+ height: 100vh;
+}
+
+.app-header {
+ flex-grow: 1;
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+}
+
+.main {
+ display: flex;
+ flex-direction: column;
+ flex-grow: 1;
+ overflow: auto;
+ background: white;
+}
+
+.main::-webkit-scrollbar {
+ width: 0;
+ height: 0;
+ background: inherit;
+}
+
+header {
+ background: #d2edf4;
+ background-image: linear-gradient(to bottom, #d0edf5, #e1e5f0 100%);
+ padding: 20px 15px 15px 15px;
+ position: relative;
+ box-shadow: 0 3px 3px rgba(34, 25, 25, 0.4);
+}
+
+.app-bar {
+ display: flex;
+ justify-content: space-between;
+}
+
+.app-bar h1 {
+ font-size: 1.5em;
+ margin: 0;
+ display: inline-block;
+ margin-right: 1em;
+}
+
+.task-form {
+ display: flex;
+ margin: 16px;
+}
+
+.task-form > input {
+ flex-grow: 1;
+ box-sizing: border-box;
+ padding: 10px 6px;
+ background: transparent;
+ border: 1px solid #aaa;
+ width: 100%;
+ font-size: 1em;
+ margin-right: 16px;
+}
+
+.task-form > input:focus {
+ outline: 0;
+}
+
+.task-form > button {
+ min-width: 100px;
+ height: 95%;
+ background-color: #315481;
+}
+
+.tasks {
+ list-style-type: none;
+ padding-inline-start: 0;
+ padding-left: 16px;
+ padding-right: 16px;
+ margin-block-start: 0;
+ margin-block-end: 0;
+}
+
+.tasks > li {
+ display: flex;
+ padding: 16px;
+ border-bottom: #eee solid 1px;
+ align-items: center;
+}
+
+.tasks > li > label {
+ flex-grow: 1;
+}
+
+.tasks > li > button {
+ justify-self: flex-end;
+ background-color: #ff3046;
+}
+```
+:::
+
+> If you want to learn more about this stylesheet check this article about [Flexbox](https://css-tricks.com/snippets/css/a-guide-to-flexbox/), and also this free [video tutorial](https://flexbox.io/) about it from [Wes Bos](https://twitter.com/wesbos).
+>
+> Flexbox is an excellent tool to distribute and align elements in your UI.
+
+### 5.2: Applying styles
+
+Now you need to add some elements around your components. You are going to add a `class` to your main `div` in the `App.jsx`, also a `header` element with a few `div` elements around your `h1`, and a main `div` around your form and list. Check below how it should be; pay attention to the name of the classes, they need to be the same as in the CSS file:
+
+::: code-group
+
+```jsx [imports/ui/App.jsx]
+import { createSignal, For, Show } from "solid-js";
+import { Meteor } from "meteor/meteor";
+import { Tracker } from "meteor/tracker";
+import { TasksCollection } from "../api/TasksCollection";
+import { Task } from "./Task.jsx";
+
+export const App = () => {
+ const [newTask, setNewTask] = createSignal('');
+
+ const addTask = async (event) => {
+ event.preventDefault();
+ if (newTask().trim()) {
+ await Meteor.callAsync("tasks.insert", {
+ text: newTask(),
+ createdAt: new Date(),
+ });
+ setNewTask('');
+ }
+ };
+
+ const subscription = Meteor.subscribe("tasks");
+ const [isReady, setIsReady] = createSignal(subscription.ready());
+ const [tasks, setTasks] = createSignal([]);
+
+ Tracker.autorun(async () => {
+ setIsReady(subscription.ready());
+ setTasks(await TasksCollection.find({}, { sort: { createdAt: -1, _id: -1 } }).fetchAsync());
+ });
+
+ return (
+
+
+In the next step, we are going to make this task list more interactive, for example, providing a way to filter tasks.
diff --git a/v3-docs/docs/tutorials/solid/6.filter-tasks.md b/v3-docs/docs/tutorials/solid/6.filter-tasks.md
new file mode 100644
index 0000000000..75679904e3
--- /dev/null
+++ b/v3-docs/docs/tutorials/solid/6.filter-tasks.md
@@ -0,0 +1,322 @@
+## 6: Filter tasks
+
+In this step, you will filter your tasks by status and show the number of pending tasks.
+
+### 6.1: Reactive State
+
+First, you will add a button to show or hide the completed tasks from the list.
+
+In Solid, we manage component state using signals for reactivity. Solid's fine-grained reactivity will automatically update the UI when the state changes.
+
+We'll add a `hideCompleted` variable to the `App.jsx` component and a function to toggle it.
+
+::: code-group
+
+```jsx [imports/ui/App.jsx]
+import { createSignal, For, Show } from "solid-js";
+import { Meteor } from "meteor/meteor";
+import { Tracker } from "meteor/tracker";
+import { TasksCollection } from "../api/TasksCollection";
+import { Task } from "./Task.jsx";
+
+export const App = () => {
+ const [newTask, setNewTask] = createSignal('');
+ const [hideCompleted, setHideCompleted] = createSignal(false); // [!code highlight]
+
+ const addTask = async (event) => {
+ event.preventDefault();
+ if (newTask().trim()) {
+ await Meteor.callAsync("tasks.insert", {
+ text: newTask(),
+ createdAt: new Date(),
+ });
+ setNewTask('');
+ }
+ };
+
+ const toggleHideCompleted = () => { // [!code highlight]
+ setHideCompleted(!hideCompleted()); // [!code highlight]
+ }; // [!code highlight]
+
+ const subscription = Meteor.subscribe("tasks");
+ const [isReady, setIsReady] = createSignal(subscription.ready());
+ const [tasks, setTasks] = createSignal([]);
+
+ Tracker.autorun(async () => {
+ setIsReady(subscription.ready());
+ setTasks(await TasksCollection.find({}, { sort: { createdAt: -1, _id: -1 } }).fetchAsync());
+ });
+
+ // markup will be updated in next steps
+};
+```
+:::
+
+Then, add the button in the markup to toggle the state:
+
+::: code-group
+
+```jsx [imports/ui/App.jsx]
+// ... javascript above remains the same
+
+return (
+
+
+You can also see all the messages that Meteor is sending and receiving from the server, this is useful for you to learn more about how Meteor works.
+
+
+
+Install it in your Google Chrome browser using this [link](https://chrome.google.com/webstore/detail/meteor-devtools-evolved/ibniinmoafhgbifjojidlagmggecmpgf).
+
+### 6.5: Pending tasks
+
+Update the App component in order to show the number of pending tasks in the app bar.
+
+You should avoid adding zero to your app bar when there are no pending tasks. Use the reactive `incompleteCount` in the header:
+
+::: code-group
+
+```jsx [imports/ui/App.jsx]
+// ... javascript with incompleteCount remains the same
+
+return (
+
+
+
+In the next step we are going to include user access in your app.
diff --git a/v3-docs/docs/tutorials/solid/7.adding-user-accounts.md b/v3-docs/docs/tutorials/solid/7.adding-user-accounts.md
new file mode 100644
index 0000000000..23d78a2682
--- /dev/null
+++ b/v3-docs/docs/tutorials/solid/7.adding-user-accounts.md
@@ -0,0 +1,414 @@
+## 7: Adding User Accounts
+
+### 7.1: Password Authentication
+
+Meteor already comes with a basic authentication and account management system out of the box, so you only need to add the `accounts-password` to enable username and password authentication:
+
+```shell
+meteor add accounts-password
+```
+
+> There are many more authentication methods supported. You can read more about the accounts system [here](https://v3-docs.meteor.com/api/accounts.html).
+
+We also recommend you to install `bcrypt` node module, otherwise, you are going to see a warning saying that you are using a pure-Javascript implementation of it.
+
+```shell
+meteor npm install --save bcrypt
+```
+
+> You should always use `meteor npm` instead of only `npm` so you always use the `npm` version pinned by Meteor, this helps you to avoid problems due to different versions of npm installing different modules.
+
+### 7.2: Create User Account
+
+Now you can create a default user for our app, we are going to use `meteorite` as username, we just create a new user on server startup if we didn't find it in the database.
+
+::: code-group
+
+```js [server/main.js]
+import { Meteor } from 'meteor/meteor';
+import { Accounts } from 'meteor/accounts-base'; // [!code highlight]
+import { TasksCollection } from '/imports/api/TasksCollection';
+import "../imports/api/TasksPublications";
+import "../imports/api/TasksMethods";
+
+const SEED_USERNAME = 'meteorite'; // [!code highlight]
+const SEED_PASSWORD = 'password'; // [!code highlight]
+
+Meteor.startup(async () => {
+ if (!(await Accounts.findUserByUsername(SEED_USERNAME))) { // [!code highlight]
+ await Accounts.createUser({ // [!code highlight]
+ username: SEED_USERNAME, // [!code highlight]
+ password: SEED_PASSWORD, // [!code highlight]
+ }); // [!code highlight]
+ } // [!code highlight]
+
+ ...
+});
+```
+:::
+
+You should not see anything different in your app UI yet.
+
+### 7.3: Login Form
+
+You need to provide a way for the users to input the credentials and authenticate, for that we need a form.
+
+Our login form will be simple, with just two fields (username and password) and a button. You should use `Meteor.loginWithPassword(username, password)`; to authenticate your user with the provided inputs.
+
+Create a new component `Login.jsx` in `imports/ui/`:
+
+::: code-group
+
+```jsx [imports/ui/Login.jsx]
+import { createSignal } from "solid-js";
+import { Meteor } from "meteor/meteor";
+
+export const Login = () => {
+ const [username, setUsername] = createSignal('');
+ const [password, setPassword] = createSignal('');
+
+ const login = async (event) => {
+ event.preventDefault();
+ await Meteor.loginWithPassword(username(), password());
+ };
+
+ return (
+
+ );
+};
+```
+:::
+
+Be sure also to import the login form in `App.jsx`.
+
+::: code-group
+
+```jsx [imports/ui/App.jsx]
+import { ReactiveVar } from 'meteor/reactive-var';
+import { createSignal, For, Show, createEffect } from "solid-js";
+import { Meteor } from "meteor/meteor";
+import { Tracker } from "meteor/tracker";
+import { TasksCollection } from "../api/TasksCollection";
+import { Task } from "./Task.jsx";
+import { Login } from "./Login.jsx"; // [!code highlight]
+
+// ... rest of the script
+```
+:::
+
+Ok, now you have a form, let's use it.
+
+### 7.4: Require Authentication
+
+Our app should only allow an authenticated user to access its task management features.
+
+We can accomplish that by rendering the `Login` component when we don’t have an authenticated user. Otherwise, we render the form, filter, and list.
+
+To achieve this, we will use a conditional `
+
+
+In the next step, we are going to learn how to deploy your app!
diff --git a/v3-docs/docs/tutorials/solid/8.deploying.md b/v3-docs/docs/tutorials/solid/8.deploying.md
new file mode 100644
index 0000000000..589ab8d062
--- /dev/null
+++ b/v3-docs/docs/tutorials/solid/8.deploying.md
@@ -0,0 +1,98 @@
+## 8: Deploying
+
+Deploying a Meteor application is similar to deploying any other Node.js app that uses websockets. You can find deployment options in [our guide](https://guide.meteor.com/deployment), including Meteor Up, Docker, and our recommended method, Galaxy.
+
+In this tutorial, we will deploy our app on [Galaxy](https://galaxycloud.app/), which is our own cloud solution. Galaxy offers a free plan, so you can deploy and test your app. Pretty cool, right?
+
+
+### 8.1: Create your account
+
+
+You need a Meteor account to deploy your apps. If you don’t have one yet, you can [sign up here](https://cloud.meteor.com/?isSignUp=true).
+With this account, you can access our package manager, [Atmosphere](https://atmospherejs.com/), [Forums](https://forums.meteor.com/) and more.
+
+
+
+### 8.2: Set up MongoDB (Optional)
+
+
+As your app uses MongoDB the first step is to set up a MongoDB database, Galaxy offers MongoDB hosting on a free plan for testing purposes, and you can also request for a production ready database that allows you to scale.
+
+In any MongoDB provider you will have a MongoDB URL which you must use. If you use the free option provided by Galaxy, the initial setup is done for you.
+
+Galaxy MongoDB URL will be like this: `mongodb://username: